虚继承 是面向对象编程中的一种技术,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。形式:在继承定义中包含了virtual关键字的继承关系,如下图中,类A就叫做虚基类。
虚拟继承是多重继承中的菱形继承所特有的概念。虚拟基类是为解决多重继承而出现的。
菱形继承中既有多继承,如下图所示:
菱形继承中也有多重继承:

现实中的例子:

问题来了:在类D的实例中将有两份类A的变量,这种数据冗余的现象我们不能容忍其存在?这就会需要用到虚继承!!!废话不多说直接上代码,直接粘贴可用。

#include <iostream>

#include <stdlib.h>
#include <string>
using namespace std;

/**
 * 定义人类: Person
 */
class Person
{
public:
    Person(string color = "blue"):m_strColor(color)
{
cout << "Person" << endl;
}
~Person()
{
cout << "~Person" << endl;
}
void eat()
{
        cout << m_strColor << endl;
        // cout << m_iAge << endl;
cout << "Person -- eat" << endl;
}
protected:
    string m_strColor;
};

/**
 * 定义工人类: Worker
 * 虚继承人类
 */
class Worker :  virtual public Person
{
public:
Worker(string name,string color):Person("Worker"+color)
{
m_strName = name;
cout << "Worker" << endl;
}
~Worker()
{
cout << "~Worker" << endl;
}
void work()
{
cout << m_strName << endl;
cout << "work" << endl;
}
protected:
string m_strName;
};

/**
 * 定义儿童类:Children
 * 虚继承人类
 */
class Children : virtual public Person
{
public:
Children(int age,string color):Person("Children"+ color)
{
m_iAge = age;
cout << "Children" << endl;
}
~Children()
{
cout << "~Children" << endl;
}
void play()
{
        cout<<
cout << m_iAge << endl;
cout << "play" << endl;
}
protected:
int m_iAge;
};

/**
 * 定义童工类:ChildLabourer
 * 公有继承工人类和儿童类
 */
class ChildLabourer:public Children,public Worker
{
public:
ChildLabourer(string name, int age,string color):Worker(name,color),Children(age,color)
{
cout << "ChildLabourer" << endl;
}

~ChildLabourer()
{
cout << "~ChildLabourer" << endl;
}
};

int main(void)
{
    // 用new关键字实例化童工类对象
ChildLabourer * p = new ChildLabourer("qq",14,"yellow");
    // 调用童工类对象各方法。
//   p->eat();
        p->Worker::eat();
        p->Children::eat();
p->work();
p->play();
delete p;
p = NULL;

return 0;

}

输出:

Person
Children
Worker
ChildLabourer
blue
Person -- eat
blue
Person -- eat
qq
work
0x60314814
play
~ChildLabourer
~Worker
~Children
~Person

如果不加virtual关键字时候的输出:

Person
Children
Person
Worker
ChildLabourer
Workeryellow
Person -- eat
Childrenyellow
Person -- eat
qq
work
0x60310814
play
~ChildLabourer
~Worker
~Person
~Children
~Person

分析:

(1)不加virtual情况:

不加virtual,也就是不是虚继承的情况下,在实例化童工这个类的时候,会按继承顺序,先调用类Children的构造函数再调用类Worker的构造函数,最后调用自己的构造函数,而调用Children和Worker的构造函数的时候又会分别先调用它们的基类Person的构造函数,这样就会生成两个Person的对象,从而生成两份Person所含有的数据成员,即童工类ChildLabourer在实例化的时会生成在内存中会生成两份Person的数据成员,所以在调用Children和Worker的eat()函数的时候,会分别打印出Workeryellow和Childrenyellow,(这里注意Children和Worker里面的eat()都是从Person继承来的,因此分别都会打印出Person --eat;还要注意调用方式:p->Worker::eat();p->Children::eat())

销毁对象时,会先调用自己的析构函数,再调用两个基类的析构函数,两个基类的析构函数调用之前都会先调用Person的析构函数。调用析构函数的顺序和调用构造函数相反。

(2)加virtual的情况:

加virtual以后,从输出结果可以看出,在实例化童工类ChildrenLabourer时,构造函数的调用顺序比较正常,只调用了一次Person,析构函数的调用也只会调用一次Person的析构函数,这说明实例化童工类时只会生成一份Person的对象,表明了在对象的内存空间中仅仅能够包含一份虚基类的对象,而且打印的结果都是blue,即ChildrenLabourer的数据不会再传入虚基类Person。这就讲数据冗余的问题解决了。

多重继承之虚继承(主要是为了解决产生的数据冗余问题)相关推荐

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

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

  2. c++primer 笔记03多重继承与虚继承

    18.3多重继承与虚继承 多个直接基类中产生派生类的能力,多重继承的派生类继承了所有父类的属性 18.3.1多重继承 派生类的派生列表中可以包含多个基类,但这些类不能是final的 class Zoo ...

  3. Th3.15:继承的构造函数、多重继承、虚继承之详述

     本博客将记录:新经典课程知识点的第15节的笔记! 本小节的知识点分别是继承的构造函数.多重继承.虚继承. 今天总结的知识分为以下5个点: (1)继承的构造函数 (2)多重继承     (2.1)多重 ...

  4. 多重继承、虚继承与虚基类

    一.多重继承 单重继承--一个派生类最多只能有一个基类 多重继承--一个派生类可以有多个基类 class 类名: 继承方式 基类1,继承方式 基类2,-. {-.}; 派生类同时继承多个基类的成员,更 ...

  5. C++基本概念复习之二:多重继承、虚继承、纯虚函数(抽象类)

    一.多重继承: #include <iostream> using namespace std; class Horse { public: Horse(){cout<<&qu ...

  6. C++基础学习-26继承的构造函数、多重继承、虚继承

    目录 继承的构造函数 多重继承 1.多重继承的概念 2.静态成员变量 3.派生类构造函数与析构函数 4.从多个父类继承构造函数 类型转换 虚基类.虚继承(虚派生) 总结 继承的构造函数 C++语言同时 ...

  7. C++学习笔记day47-----C++98-继承中的构造函数,析构函数,拷贝构造函数,拷贝赋值函数,多重继承,虚继承

    继承中的构造函数 当通过一个子类创建一个新的对象时,编译器会根据子类在初始化表中指明的基类的初始化方式去调用基类相应的构造函数.如果子类的初始化表中,并没有指明基类的初始化方式,编译器将会调用基类的无 ...

  8. 多重继承和虚继承的内存布局

    这篇文章主要讲解虚继承的C++对象内存分布问题,从中也引出了dynamic_cast和static_cast本质区别.虚函数表的格式等一些大部分C++程序员都似是而非的概念.原文见这里 (By Eds ...

  9. C++继承的构造函数、多重继承、虚继承

    一.继承 继承性是面向对象程序设计的第二大特性,它允许在既有类的基础上创建新类,新类可以继承既有类的数据成员和成员函数,可以添加自己特有的数据成员和成员函数,还可以对既有类中的成员函数重新定义.利用类 ...

最新文章

  1. 判断32位整数二进制中1的个数
  2. 页面性能优化详细总结
  3. 价值观对做产品的三点影响
  4. QT的QFutureIterator类的使用
  5. 如何建立一个完整的游戏AI
  6. int取值范围的注意问题
  7. 51nod 1062 序列中最大的数【打表】
  8. 第四季 word vba
  9. QQ、空间、新浪微博、微信分享
  10. PDf无法双面打印解决方式
  11. 小波变换(matlab)-常见脚本函数
  12. Pascal VOCdata数据集读取(pytorch)
  13. 从技术实现到安全运行,工程师版“元宇宙”离我们还有多远?
  14. VUE中使用高德地图.做个轨迹添加器,为路线规划做数据
  15. 产品经理 : 最全的运营数据指标解读
  16. VS2017如何设置C++11?
  17. 无线网卡在服务器上不能启用,解决无线网卡突然不能启用的问题(事件ID4294)...
  18. CSP2020-J1-真题解析-完善程序
  19. 在Excel中快速输入时间精确到秒
  20. 【javaWeb微服务架构项目——乐优商城day03】——(搭建后台管理前端,Vuetify框架,使用域名访问本地项目,实现商品分类查询,cors解决跨域,品牌的查询)

热门文章

  1. PHPcurl抓取AJAX异步内容(转载)
  2. [LeetCode] Maximal Rectangle
  3. python 选择多个文件夹_如何同时选择多个文件?
  4. mysql 查看锁表日志_MYSQL 表锁情况查看
  5. 引导界面图标好大_游戏里那些图标和界面,原来是这么设计出来的?
  6. 灵格斯怎么屏幕取词_电脑包尺寸怎么选?手提的好还是双肩的好?比较推荐哪款电脑包?...
  7. mysql 从库_mysql数据库主从配置
  8. linux怎么进入文件夹_Linux基础命令《上》
  9. edp1.2和edp1.4_EDP​​的完整形式是什么?
  10. console java_Java Console format()方法与示例