1.继承
-
一个class,会生成默认构造,默认解析,默认拷贝构造,重载=
-
继承:会继承父类所有成员,继承可以制定继承方式(访问控制),有public,project,private,继承方式影响继承后的属性的访问权限
-
继承:
- 直接继承父类成员
- 修改父类成员权限/在子类定义同名成员,隐藏父类成员
- 定义新的变量和新的函数
-
权限:
- 私有:对外部(包含子类)都是不可访问
- 受保护:对外部(不包含子类)不可以访问 子类可以访问
- 公有:外部可以随意访问
-
构造、析构不会被继承,但可以调用
class A{
A():{}
A(int x){}
~A():{}
}
class B:pulic A{
B():{}
B(int a):{}
B(int x,int y)A(x){}
~B():{}
}
int main(void){
B a;
B b(2);
B c(2,4);
return 0;
}
-
过程分析
- B a;的过程,先调用父类A的无参构造函数,再调用B的无参构造函数,函数结束时,调用A的析构函数,再调用B的析构函数 A->B->B->A
- B a(2);的过程,先调用父类A的无参构造函数,再调用B的有参构造函数,函数结束时,调用A的析构函数,再调用B的析构函数 A->B->B->A
- B c(2,4);先调用父类A的有参构造函数,再调用B的有参构造函数,函数结束时,调用A的析构函数,再调用B的析构函数 A->B->B->A;
-
想要调用A的有参构造,必须显示指出调用哪个,必须在初始化形参列表中明确指明调用A的哪个构造
-
调用析构会调用父类的析构,析构只有一个,没必要指明
-
子类和父类如果有同名成员,父类的会被隐藏,依然占内存
-
可以使用父类名字调用
-
B继承A会有一个继承方式,A中的成员在B中有不同的继承方式
-
父类中的私有成员对外部(包含子类)都是不可访问的
-
父类的私有成员继承到子类,可以通过成员变量或者友元进行访问
-
继承用‘:'冒号表示
-
多个继承之间用’,‘逗号隔开
- 运算符:函数的名字
- 运算结果 :返回值
-
通过
#pragma once
class num
{
int x;
public:
num();
num(const num& other); // 拷贝构造的形参,必须是引用,可以不加const
~num();
num operator+(num& b); // 运算符重载
};
——————————————————————————————————————
num num::operator+(num& b) {
num sum; // 用来存放结果
sum.x = this->x + b.x;
return sum;
}
class Xnum:num
{
int x;
}
xx = Xnum;
xx.x;
num::x;
多继承
- 如果是多继承,那么子类会同时存在来自于所有父类的成员
class A
{
x =1;
z =2;
}
class B
{
y = 1;
z = 3;
}
class C:public A,public B
{
this->A:z;
this->B:z;
}
- 多继承优先使用子类的成员,父类被隐藏,如果变量名重载,需要额外地用父类名字去加以区分
结构体也有继承,结构体默认公有继承
struct A:struct B;
虚继承(菱形继承)
- 菱形继承:A派生出B、C, B、C共同派生出D
class A{}
class B: public virtual A{}
class C: public virtual A{}
class D: public B, public C{}
个人理解:
- B虚继承与A,本质上B继承了一个指向A成员的指针
- C虚继承与A,本质上B继承了一个指向A成员的指针
- D继承与B、C,本质上继承了B和A中的指针,由于两个指针指向同一块内存地址,因此无论调用哪个都可以
- 而虚继承解决了多继承中可能出现的问题,两个相同的成员,共用一个内存地址,节省了内存空间