c++类基础知识
数据访问权限
形式 | 内部 | 外部 | 继承类 |
---|---|---|---|
public | 可用 | 可用 | 可用 |
private | 可用 | 不可用 | 不可用 |
protected | 可用 | 不可用 | 可用 |
注:默认priavte |
继承方式
形式 | public | protected | private |
---|---|---|---|
public继承 | public | protected | 不可见 |
protected继承 | protected | protected | 不可见 |
private继承 | private | private | 不可见 |
注:默认priavte |
类与类的关系
继承(Generalization)
继承是面向对象的三大特征之一,是一种最能体现面向对象代码复用的类关系,对于继承,可以使用"is a"来表示,比如,小轿车(类B)"is a"车(类A),是对车(类A)的进一步刻画,那么这两个类就是"继承"关系。
class Goose : public Bird{
//子类扩展属性和方法
};
组合(Composition)
组合是将一个对象(部分)放到另一个对象里(组合)。它是一种 "has-a" 的关系。相比"聚合",组合是一种强所属关系,组合关系的两个对象往往具有相同的生命周期,被组合的对象是在组合对象创建的同时或者创建之后创建,在组合对象销毁之前销毁。一般来说被组合对象不能脱离组合对象独立存在,而且也只能属于一个组合对象。比如,鸟类和翅膀类就是组合关系,在创建一个鸟类对象时,一定要同时或之后创建一个翅膀类对象,销毁一个鸟类对象时,一定要先同时或之前销毁翅膀对象。
在C++语法中,使用在一个类中包含另外一个类类型的成员来实现组合。
class Wing{
};
class Bird{
Wing wing;
};
聚合(Aggregation)
聚合是一种弱所属关系,比如一只大雁和雁群,就是一种"聚合"关系。和组合相比,被聚合的对象可以属于多个聚合对象,比如,一只大雁可能属于多个雁群。
在C++语法中,通过类的指针来实现聚合
class Goose{
};
class Geese{
public:
Goose member[10];
};
关联(Association)
关联也是一种弱关系,但并不是从属关系,关联的连个的类可以看作是平等的,比如一只大雁和老鹰的关系,就可以看作关联关系
C++中,通过定义其他类指针类型的成员来实现关联,下面是双向关联的实现方法
class Egle{
class Goose *food;
};
class Goose{
class Egle *predator;
};
依赖(Dependency)
一个对象的某种行为依赖于另一个类,比如,大雁的迁徙行为受季节影响,那么,大雁和季节就会有"依赖"关系。
C++语法中,通过将一个类作为另一类方法的参数的形式实现两个类之间的依赖关系
class Season{
};
class Goose{
public:
void Migrate(Season season); //或Migrate(Season *season)、Migrate(Season &season)
};
实现(Realization)
实现对应的是面向对象中的"接口",即动物都要移动,但是每种移动的方式不一样,鸟要实现自己独有的移动的方法。
在C++中,接口通过的纯虚函数来实现,C++的多态就是通过虚函数来实现的。
class Animal{
public:
vitual void move();
};
class Bird: public Animal{
void move(){
//鸟的移动方式,飞
}
};
友元
友元函数
友元函数可以访问类的private和protected,但声明只能出现在类定义的内部,由于不是类本身的函数,所以可以在public、private和protected中声明,其本身是定义在类外的普通函数。
class test
{
private:
int n;
friend void f(test &a);
};
void f(test &a)
{
a.n = 100;
}
类函数作为另一个类的友元函数
class B;
class A
{
public:
void f(B &b);
};
class B
{
private:
firned void A::f(B &b);
}
void A::f(B &b)
{
}
友元类
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的private和protected的数据。
class B;
class A
{
private:
int n;
friend class B;
};
class B
{
public:
void f(A &a);
};
void B::f(A &a)
{
a.n = 100;
}
注意事项
- 友元关系不存在传递性,即每个类负责控制自己的友元类或者友元函数;
- 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
- 友元关系不能被继承。
类的常量
方法1:定义属于这个类范围的常量
class test
{
private:
enum {Months = 12};
};
这种声明枚举不会创建类数据成员,这里枚举只是为了创建类数据成员,因此不用提供枚举名。类似上面的例子还有ios_base::fixed
等。
c++11作用域内的枚举
enum egg {Small, Medium, Large, Jumbo};
enum t_shirt {Small, Medium, Large, Xlarge};
编译器提示重复定义Small
、Medium
、Large
和Jumbo
。因为egg Small和t_shirt Small位于相同的作用域内。
c++11提供了一种新的枚举,它的作用域为类。可以使用关键字class
或者struct
。
enum class egg {Small, Medium, Large, Jumbo};
enum class t_shirt {Small, Medium, Large, Xlarge};
egg choice = egg::Large;
t_shirt Floyd = t_shirt::Large;
const常量
class test
{
private:
const int n;
public:
test():n(100){}
}
类的声明只是声明了类的形式,并没有创建对象,因此,在创建对象前,将没有用于储存值的空间。
c++98与c++11的区别
在C++98标准里,只有static const声明的整型成员能在类内部初始化,并且初始化值必须是常量表达式。这些限制确保了初始化操作可以在编译时期进行。
class X {
static const int m1 = 7; // 正确
const int m2 = 7; // 错误:无static
static int m3 = 7; // 错误:无const
static const string m5 = “odd”; //错误:非整型
};
C++11的基本思想是,允许非静态(non-static)数据成员在其声明处(在其所属类内部)进行初始化。这样,在运行时,需要初始值时构造函数可以使用这个初始值。现在,我们可以这么写:
class A {
public:
int a = 7;
};
//它等同于使用初始化列表:
class A {
public:
int a;
A() : a(7) {}
};
c++11这样的好处就是当构造函数需要多个初始化时就会变得很简洁。
重载
函数重载
运算符重载
重载规则
- 不可重载的运算符:
.
;.*
;sizeof
;?::
- 不能创建新的运算符
- 不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
友元重载运算符
运算符函数重载一般有两种形式:重载为类的成员函数和重载为类的非成员函数(通常是友元)
class test
{
private:
int value;
public:
int operator()(int a,int b)const
{
return value + a + b;
}
};
重载(),可以自己选择参数的数量以及返回值类型
只能用成员函数重载而不能用友元的运算符:=
;()
;[]
;->
不可以产生二义性
class test
{
private:
int value;
public:
test operator+(const test &b)const
{
test sum;
sum.value = this -> value + b.value;
return sum;
}
friend test operator+(const test &a,const test &b)
{
test sum;
sum.value = a.value + b.value;
return sum;
}
};
int main()
{
test a,b;
test c = a + b;//c = a.operator+(b) or c = operator+(a,b)
return 0;
}
一般来说选择参数少的写法,也就是成员函数
一些知识点
由于前置++(--)和后置++(--)符号一样,所以需要特别区分,后置的在参数填个int
。
class test
{
private:
int value;
public:
test& operator++()
{
++value;
return *this;
}
test operator++(int)
{
test temp(*this);
++value;
return temp;
}
};
class test
{
private:
int value;
public:
int operator()(int a,int b)const
{
return value + a + b;
}
};
强制转换不需要写返回值
class test
{
private:
int value;
public:
operator int()const
{
return value;
}
};
int main()
{
test a;
int x = int(a);
return 0;
}
关于两种强制转换的写法,C语言的写法:(int)a
,如果要进行强制类型转换的对象是一个变量,该变量可以不用括号括起来。如果要进行强制类型转换的对象是一个包含多项的表达式,则表达式应该用括号括起来。C++写法:int(a)
。
类中的其他关键字
delete
未完待续