继承
语法:
class 子类 :继承方式 父类
继承方式:
public: 公有继承
通过公有继承-->私有权限不会被继承,父类中的公有权限在子类中还是公有权限,保护权限在子类中还是保护权限
protected:保护继承
通过保护继承-->私有权限不会被继承,父类中的公有权限和保护权限在子类中变为保护权限
private:私有继承
通过私有继承-->私有权限不会被继承,父类中的公有权限和保护权限在子类中变为私有权限
继承中的对象模型
- 子类会继承父类中所有的内容,包括了私有属性
- 只是我们访问不到,编译器给隐藏了
通过vs的Developer Command Prompt工具,可以查看单类的数据结构。
查看命令:
cl /d1 reportSingleClassLayout+类名 +空格+ 类所在文件名
继承中的构造和析构顺序
子类是不会继承父类的构造函数和析构函数、=号函数
子类创建对象时,先调用父类的构造,然后调用自身构造
析构顺序和构造顺序相反
-
如果父类中没有合适默认构造,那么子类可以利用初始化列表的方式显示的调用父类的其他构造
例:
class Base
{
public:
Base(int A)
{
this->A = A;
}
private:
int A;
};
//利用初始化列表方式 显示调用
class Son:public Base
{
public:
Son(int a) :Base(a)
{
}
};
继承中的同名成员处理
成员属性 直接调用先调用子类,如果想调用父类 需要作用域
-
成员函数 直接调用先调用子类,父类的所有版本都会被隐藏,除非显示用作用域运算符去调用
子类+.+父类名::+成员属性 子类::+父类名::+\成员函数
继承中的静态成员处理
- 静态成员属性 子类可以继承下来
- 静态成员函数 类似非静态成员函数处理,如果想访问父类的,加作用域即可
多继承
- 多继承会带来一些二义性的问题,如果两个基类中有同名的函数或者变量,那么通过派生类对象去访问这个函数或变量时就不能明确到底调用从基类1继承的版本还是从基类2继承的版本。
- 解决方式:显示指定调用那个基类的版本。
- 不建议使用多继承
菱形继承和虚继承
两个派生类继承同一个基类而又有某个类同时继承这两个派生类,这种继承被称为菱形继承或者钻石型继承。
菱形继承
菱形继承会导致数据浪费(出现两次)解决问题利用虚基类
例:
class Animal
{
public:
Animal()
{
A = 10;
}
Animal(int A)
{
this->A = A;
}
int A;
};
class Sheep:public Animal
{
};
class Tuo :public Animal
{
};
class SheepTuo :public Sheep, public Tuo
{
};
void test()
{
SheepTuo st;
st.Sheep::A = 10;
st.Tuo::A = 20;
cout << st.Sheep::A << endl;
cout << st.Tuo::A << endl;
}
SheepTuo结构图
虚基类继承
继承时在权限前面,冒号后面加上virtual关键字
vbptr 虚基类指针
指向一张虚基类表
通过表找到偏移量
找到共有数据
例:
class Animal
{
public:
Animal()
{
A = 10;
}
Animal(int A)
{
this->A = A;
}
int A;
};
class Sheep:virtual public Animal
{
};
class Tuo :virtual public Animal
{
};
class SheepTuo :public Sheep, public Tuo
{
};
void test()
{
SheepTuo st;
st.Sheep::A = 10;
st.Tuo::A = 20;
cout << st.Sheep::A << endl;
cout << st.Tuo::A << endl;
}
结构图:
此时数据只有一份。vbptr是virtual base pointor缩写,是一个虚指针。