目录

  • 继承的构造函数
  • 多重继承
    • 1.多重继承的概念
    • 2.静态成员变量
    • 3.派生类构造函数与析构函数
    • 4.从多个父类继承构造函数
  • 类型转换
  • 虚基类、虚继承(虚派生)
  • 总结

继承的构造函数

  1. C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。
  2. 继承时,子类只能继承其直接基类(父类)的构造函数。默认(也即编译器自动给我们生成的)、拷贝、移动构造函数都是不能被继承的。那么怎么写继承的构造函数呢?
    格式:using 类名::类名(构造函数名);
class A {public:A(int i,int j,int k){}public:static int m_static;
};
int A::m_static = 100; //后续要使用的话必须初始化,不使用的话可以不用定义class B : public A {public://B(int i,int j,int k):A(i,j,k) {};using A::A;//继承A的构造函数,会把基类都生成与之对应的派生类构造函数//B(int i,int j,int k):A(i,j,k) {};//如果有默认参数的话,会构造多个派生类构造函数//一个默认参数就会生成2个构造函数//A(int i,int j,int k=5){} ;//B(int i,int j,int k):A(i,j,k) {};//B(int i,int j):A(i,j) {};
};int main () {B test(10,20,3);return 1;
}
  1. 如果子类中只含有使用using 类名::类名;继承过来的构造函数时,编译器不认为我们给该子类定义了构造函数的。因此编译器还会为我们自动生成子类的默认构造函数
  2. 如果基类的构造函数中带有默认的参数值,那么编译器一遇到using A::A;时,就会帮我们在子类中构造出多个构造函数来.

多重继承

class grand
{public:grand(int v):m_valuegrad(v) {cout << "grand的构造函数" << endl;};~grand() {cout << "grand的析构函数" << endl;}void initData() {cout << "grand initData" << endl;}void init() {cout << "grand init" << endl;}static int valuegrand;int m_valuegrad;
};int grand::valuegrand = 100;class A1 : public grand
{public:A1(int v):grand(v),m_valuea1(v)  {cout << "A1的构造函数" << endl;};~A1() {cout << "A1的析构函数" << endl;}void initData() {cout << "A1 initData" << endl;}int m_valuea1;
};class B1
{public:B1(int v):m_valueb1(v) {cout << "B1的构造函数" << endl;};~B1() {cout << "B1的析构函数" << endl;};void initData() {cout << "B1 initData" << endl;}int m_valueb1;
};class C: public B1 ,public A1
{public:C(int v):B1(v),A1(v),m_valuec(v) {cout << "C的构造函数" << endl;};~C() {cout << "C的析构函数" << endl;}int m_valuec;
};

1.多重继承的概念

一个子类继承自多个(2个及以上)父类。

2.静态成员变量

int grand::valuegrand = 100;
后续要使用的话必须初始化,不使用的话可以不用定义。
类跟类对应的对象都可以使用。

int main () {C c(1);c.init();//会调用基类grandc.A1::initData();//2个父类有同名函数需要标明具体类名c.B1::initData();c.valuegrand = 10000;A1::valuegrand = 1000;C::valuegrand = 1000;cout << c.valuegrand << endl;return 1;
}

3.派生类构造函数与析构函数

  1. 构造一个派生类对象将同时构造并初始化所有的直接基类的成分。
  2. 派生类的构造函数初始化列表只初始化它的直接基类,在多继承时也不例外。这样就会一层一层地把参数传递回最原始的基类,并把all的基类成分都构造好。
  3. 基类的构造顺序跟“派生列表”中基类的出现顺序是保持一致的!析构顺序则相反。
  4. 每个类的析构函数都只会进行自己这个类本身的成分的释放工作(类与类之间的析构函数是互不干扰的)。

4.从多个父类继承构造函数

class A {public:A(int tv) {}
};
class B {public:B(int tv) {}
};
class C : public A,public B {public:using A::A;//继承A类的构造函数 ==> C(int tv):A(tv){}using B::B;//错误!继承B类的构造函数是 ==> C(int tv):B(tv){}该构造函数和继承自A类的一模一样
};

上述code中C多继承自父类A和父类B的构造函数已经重定义了。因此我们只能自己定义一个属于子类C的构造函数,应该在C中添加:

C(int tv):A(tv),B(tv){cout << "C类的构造函数执行了!" << endl;}

类型转换

基类指针是可以指向一个派生类(子类)对象的:因为编译器会帮助我们隐式地执行这种派生类到基类的转换。究其原因:因为每个派生类对象都会包含基类对象的成分。在多继承中,基类指针也是可以指向一个派生类(子类)对象的!

    grand *g = new C(1);A1 *a = new C(1);B1 *b = new C(1);C tc(2);grand gg(tc);

这些写法都是正确的。

虚基类、虚继承(虚派生)

派生列表中,同一个基类只能出现一次,但是如下两种特殊情况例外:

  1. 派生类可以通过它的两个直接基类分别继承自同一个间接基类。
  2. 直接继承某个基类,然后通过另一个基类间接继承该类。
class grand
{public:grand(int v):m_valuegrad(v) {cout << "grand的构造函数" << endl;};~grand() {cout << "grand的析构函数" << endl;}void initData() {cout << "grand initData" << endl;}void init() {cout << "grand init" << endl;}static int valuegrand;int m_valuegrad;
};int grand::valuegrand = 100;class A1 : public grand
{public:A1(int v):grand(v),m_valuea1(v)  {cout << "A1的构造函数" << endl;};~A1() {cout << "A1的析构函数" << endl;}void initData() {cout << "A1 initData" << endl;}int m_valuea1;
};class A2 : public grand
{public:A2(int v):grand(v),m_valuea2(v)  {cout << "A2的构造函数" << endl;};~A2() {cout << "A2的析构函数" << endl;}int m_valuea2;
};class B1
{public:B1(int v):m_valueb1(v) {cout << "B1的构造函数" << endl;};~B1() {cout << "B1的析构函数" << endl;};void initData() {cout << "B1 initData" << endl;}int m_valueb1;
};class C: public B1 ,public A1 ,public A2
{public:C(int v):B1(v),A1(v),A2(v),m_valuec(v) {cout << "C的构造函数" << endl;};~C() {cout << "C的析构函数" << endl;}int m_valuec;
};int main() {C ccc(1);//ccc.m_valuegrad = 100;return 1;
}

运行结果为:

可以发现grand调用了2次构造2次析构函数。当调用共享基类的成员是会出现不明确错误。这就是多继承时对于基类成员变量的二义性问题
比如 ccc.m_valuegrad = 100; 提示C::m_valuegrad" 不明确。为了解决这样的错误同时为了提高效率,怎么才能调用一个呢?
只需在A1和A2继承grand的添加virtual。
class A1 :virtual public grand
class A2 :virtual public grand
同时把C(int v):B1(v),A1(v),A2(v),m_valuec(v)改为
C(int v):B1(v),A1(v),A2(v),gand(v),m_valuec(v)
修改之后再次运行结果为:
OK,完美!

总结

  1. 若非必要,请一定不要选择用多继承的方式来编写你的代码!十分重要到建议:能用单继承解决问题,就不要用多继承!能不用virtual虚继承就尽量不用virtual继承来写代码!
  2. 若实在必要用到多继承时,提醒自己到底是否需要用虚继承的方式来进行多继承!(当产生成员变量的二义性问题时,就需要用虚继承来进行多继承!)。
  3. 学习多继承这个知识点不是说你一定要去常用它,而是为了让你去阅读别人的代码时不发懵!

C++基础学习-26继承的构造函数、多重继承、虚继承相关推荐

  1. 【C++】继承和派生、虚继承和虚基类、虚基类表和虚基类指针

    继承和派生.虚继承和虚基类.虚基类表和虚基类指针 继承和派生 继承概述 继承基本概念 派生类中的成员 继承的内容 派生类定义 派生类访问控制 对象构造和析构 对象构造和析构的调用顺序 继承中的构造和析 ...

  2. C++ Primer 5th笔记(chap 18 大型程序工具)构造函数与虚继承

    1. 继承体系中的每个类都可能在某个时刻成为" 最低层的派生类". 只要我们能创建虚基类的派生类对象, 该派生类的构造函数就必须初始化它的虚基类. Bear::Bear (std: ...

  3. 6.12C++:继承基类的构造函数、单继承的构造函数、多继承的构造函数、派生类复制构造函数、派生类的析构函数

    1 继承基类的构造函数 class A{public:A(){}; // A的构造函数 }; class B : public A{public:using A:A: } 2 单继承的构造函数 cla ...

  4. 钻石问题(菱形继承问题) 和虚继承

    在C++中,什么叫做钻石问题(也可以叫菱形继承问题),怎么避免它? 下面的图表可以用来解释钻石问题. 假设我们有类B和类C,它们都继承了相同的类A.另外我们还有类D,类D通过多重继承机制继承了类B和类 ...

  5. 继承(下)----虚继承

    单继承&多继承 一个子类只有一个直接父类时称这种继承关系为单继承. 一个子类有两个或者两个以上的父类时称这种继承关系为多继承. 菱形继承 ---------特殊的多继承 有很大的缺点: 二义性 ...

  6. 多继承的二义性和虚继承(虚基类)

    一般来说,在派生类中对基类成员的访问是应该是唯一的.但是,由于在多继承的情况下,可能出现基类中某个成员的访问不唯一的情况,这称为对基类成员访问的二义性. 在多继承的情况下,通常有两种可能出现的二义性. ...

  7. Java面向对象基础学习笔记(构造、重载、继承、多态、抽象类、接口、模块)

    Java面向对象编程包含哪些内容? 怎么理解面向对象编程? 现实生活中,我们定义了"人"的抽象概念,这就是类class,生活中的每一个具体的人就是实例instance. class ...

  8. 夯实C++基础学习笔记

    第一章 内存模型和编译链接 1. 掌握进程虚拟地址空间区域划分 编程语言产生:指令+数据 exe 磁盘加载到内存,不可能直接加载到内存. x86系统:linux系统会给当前进程分配一个 2^32 大小 ...

  9. 多重继承与虚继承编程实验

    多重继承与虚继承编程实验 基本知识 多重继承 多重继承下的类作用域 虚继承 构造函数与虚继承 关于本程序 示例代码 Animal_virtual_baseVers.h virt-inherit.cpp ...

最新文章

  1. 雷军在小米直面会丢的面子,在年度演讲都找回来了
  2. sql注入及mybatis防止sql注入
  3. 什么是java?为什么大家都学习java技术?
  4. 分隔线演练-利用参数增加分隔线的灵活度
  5. python3 console input_Python3 tkinter基础 Button command 单击按钮 在console中打印文本
  6. C# —— 序列化与反序列化
  7. python方向键键值_python字典键值对的添加和遍历方法
  8. Windows编程—杀死指定路径程序文件的进程
  9. ZZULIOJ 1083: 数值统计(多实例测试)
  10. struct和typedef struct用法
  11. HTML CSS 响应式-菜单
  12. 惠普HP Laser 107a 打印机驱动
  13. 计算机设计大赛山东,第十届中国大学生计算机设计大赛山东赛区颁奖典礼在我校举办...
  14. CSS 排版与正常流 —— 重学CSS
  15. 继续当搬运工之人人网移动端架构解析
  16. MaxEnt运行错误
  17. 单片机C语言零基础入门05 - 逻辑运算
  18. 分布式、高性能和高可用解决方案 (分布式)
  19. html游戏让目标人物移动,用仿ActionScript的语法来编写html5——第三篇,鼠标事件与游戏人物移动...
  20. Sorry to Amy.

热门文章

  1. 2021年9月份全国计算机二级C真考题库下载网址大全
  2. 集团企业运营管控平台建设实施方案 集团企业信息化整体解决方案.pptx
  3. oracle resize datafile,用resize缩小datafile大小
  4. Ansible命令行工具——ansible-galaxy
  5. SpringCloud Nacos 心跳机制和服务健康检查源码解析
  6. 【转载】美工面试题总结
  7. 尝试寻找一些合作伙伴,产品相关培训咨询服务介绍(2B/支持在线)
  8. 红眼睛红外成像微型成像仪快速刷新与动态显示温度测量
  9. 【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
  10. BaseRpm 机械角度 电角速度