C++最重要的特征是代码重用,通过继承机制可以利用已有的数据类型来定义新的数据类型,新的类不仅拥有旧类的成员,还拥有新定义的成员。
例如一个B类继承于A类,或称从类A派生类B。这样的话,类A成为基类(父类),类B成为派生类(子类)。派生类中的成员,包含两大部分:一类是从基类继承过来的,一类是自己增加的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。
定义形式:
class 父类{};
class 子类:继承方式 父类名
{
//新增子类数据
};
继承方式:private protected public(推荐)
公共继承 保持不变,保护继承变保护,私有继承变私有,所有父类私有在子类中不可见。
以public为例:
class Base
{
public:
Base()
{
cout<<"父类构造函数"<
运行结果:
一般情况下,子类 会自动调用 成员对象和父类的默认构造。
调用成员对象和父类的有参构造:子类 必须使用有参构造和初始化列表
初始化列表时:父类写类名称,成员对象用对象名。
#include
#include
using namespace std;
class Base
{
public:
int a;
public:
Base()
{
cout << "父类默认构造函数" << endl;
}
Base(int a)
{
this->a = a;
cout << "父类有参构造函数" << endl;
}
~Base()
{
cout << "父类析构函数" << endl;
}
};
class Other
{
public:
int b;
public:
Other()
{
cout << "Other默认构造函数" << endl;
}
Other(int b)
{
this->b = b;
cout << "Other有参构造函数" << endl;
}
~Other()
{
cout << "Other析构函数" << endl;
}
};
class Son :public Base
{
public:
int c;
Other ob;
public:
Son()
{
cout << "子类默认构造函数" << endl;
}
//子类要给成员中b赋值,父类中的a赋值
//不能直接赋值,父类会先执行存在,调用父类默认构造
Son(int a,int b,int c):Base(a),ob(b)//用初始化列表,父类写类名称 成员对象用对象名
{
this->c=c;
cout << "子类有参构造函数" << endl;
}
~Son()
{
cout << "子类析构函数" << endl;
}
};
void test()
{
Son ob(10,20,30);
}
int main(int argc, char* argv[])
{
test();
return 0;
}
处理方式:加作用域
默认优先访问 子类的同名成员,加父类作用域 访问父类的同名成员。
注:子类会重定义父类的同名函数:
重载:无继承,同一作用域,参数的个数、顺序、类型不同 都可重载
重定义:有继承, 子类 重定义 父类的同名函数(参数可以不同)(非虚函数)
子类一旦 重定义了父类的同名函数(不管参数是否一致),子类中都将屏蔽父类所有的同名函数。必须加父类作用域 访问父类的同名成员。
class Base
{
public:
void fun()
{
cout<<"父类fun函数"<
父类的构造、析够、重载赋值运算符operator= 不能被子类 继承。
class 父类1{};
class 父类2{};
class 子类:继承方式1 父类1, 继承方式2 父类2
{
//新增子类数据
};
子类拥有父类1,父类2的大部分数据
两个派生类继承同一个基类而又有某个类同时继承者两个派生类,即有公共祖先的继承。这种继承被称为菱形继承,或者钻石型继承。
最底层的子类 数据 会包含多份公共祖先的数据和基类派生的派生类的数据
问题:
1、羊继承了动物的数据和函数,鸵同样继承了动物的数据和函数,当草泥马调用函数或者数据时,就会产生二义性,通过加作用域解决。
2、草泥马继承自动物的函数和数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以,通过虚继承解决。
class Animal
{
public:
int Data;
};
class Sheep:public Animal{};
class Tuo:public Animal{};
class SheepTuo:public Sheep,public Tuo{};
void test()
{
SheepTuo ob;
//cout<
虚继承 解决 菱形继承中 多份公共祖先数据的问题
子类虚继承父类 子类只会保存一份公共数据。
方式:在继承方式 前加virtual修饰
从电脑开始中的目录找找到 Developer Command Prompt for VS 2022 并打开
在vs复制完整路径后进入对应文件夹。
dir命令查看文件
导出单个类的布局:
cl /d1 reportSingleClassLayoutAnimal main.cpp
Sheep布局:
Tuo布局:
SheepTuo布局:
虚继承 会在子类中产生 虚基类指针(vbptr) 指向 虚基类表(vbtable), 虚基类表纪录的是 通过该指针访问公共祖先的数据的偏移量。
注意:
1、虚继承只能解决具备公共祖先的多继承所带来的二义性问题,不能解决没有公共祖先的 多继承的。
2、工程开发中真正意义上的多继承是几乎不被使用,因为多重继承带来的代码复杂性远多 于其带来的便利,多重继承对代码维护性上的影响是灾难性的,在设计方法上,任何多继承 都可以用单继承代替