【C++深度剖析教程31】被遗弃的多重继承

加qq1126137994 微信:liu1126137994

C++中是否允许一个类继承多个父类?

C++支持编写多重继承的代码:

  • 一个子类可以拥有多个父类
  • 子类拥有所有父类的成员变量
  • 子类继承父类所有的成员函数
  • 子类对象可以当做任意父类对象使用

多重继承的语法规则:
这里写图片描述

多重继承的本质与单继承相同

编程示例;

#include <iostream>
#include <string>using namespace std;class BaseA
{int ma;
public:BaseA(int a){ma = a;}int getA(){return ma;}
};class BaseB
{int mb;
public:BaseB(int b){mb = b;}int getB(){return mb;}
};class Derived : public BaseA, public BaseB
{int mc;
public:Derived(int a, int b, int c) : BaseA(a), BaseB(b){mc = c;}int getC(){return mc;}void print(){cout << "ma = " << getA() << ", "<< "mb = " << getB() << ", "<< "mc = " << mc << endl;}
};int main()
{cout << "sizeof(Derived) = " << sizeof(Derived) << endl;    // 12Derived d(1, 2, 3);d.print();cout << "d.getA() = " << d.getA() << endl;cout << "d.getB() = " << d.getB() << endl;cout << "d.getC() = " << d.getC() << endl;cout << endl;BaseA* pa = &d;BaseB* pb = &d;cout << "pa->getA() = " << pa->getA() << endl;cout << "pb->getB() = " << pb->getB() << endl;cout << endl;void* paa = pa;void* pbb = pb;if( paa == pbb ){cout << "Pointer to the same object!" << endl; }else{cout << "Error" << endl;}cout << "pa = " << pa << endl;cout << "pb = " << pb << endl;cout << "paa = " << paa << endl;cout << "pbb = " << pbb << endl; return 0;
}

运行结果:
这里写图片描述

分析以上程序我们就可以发现问题所在啦:
1、通过多重继承的对象可能拥有不同的地址
这里写图片描述
2、多重继承可能产生冗余的成员:
这里写图片描述
当多重继承关系闭合将产生数据冗余问题
解决办法是:
虚继承!!!
这里写图片描述

下面看一个解决冗余的例子:

#include <iostream>
#include <string>using namespace std;class People
{string m_name;int m_age;
public:People(string name, int age){m_name = name;m_age = age;}void print(){cout << "Name = " << m_name << ", "<< "Age = " << m_age << endl;}
};class Teacher : virtual public People
{
public:Teacher(string name, int age) : People(name, age){}
};class Student : virtual public People
{
public:Student(string name, int age) : People(name, age){}
};class Doctor : public Teacher, public Student
{
public:Doctor(string name, int age) : Teacher(name, age), Student(name, age), People(name, age){}
};int main()
{Doctor d("Delphi", 33);d.print();return 0;
}

运行结果为;
Name = Delphi, Age = 33

  1. 虚继承能够解决数据冗余的问题
  2. 中间层父类不再关心顶层父类的初始化
  3. 最终子类必须直接调用顶层父类的构造函数

虽然我们解决的数据冗余,但是还有一个问题,在架构设计师,无法确定使用虚继承还是直接继承???

3、多重继承有可能会产生多个虚函数表
这里写图片描述

#include <iostream>
#include <string>using namespace std;class BaseA
{
public:virtual void funcA(){cout << "BaseA::funcA()" << endl;}
};class BaseB
{
public:virtual void funcB(){cout << "BaseB::funcB()" << endl;}
};class Derived : public BaseA, public BaseB
{};int main()
{Derived d;BaseA* pa = &d;BaseB* pb = &d;BaseB* pbe = (BaseB*)pa;    // oops!!BaseB* pbc = dynamic_cast<BaseB*>(pa); //dynamic_cast会对指针进行修正cout << "sizeof(d) = " << sizeof(d) << endl;cout << "Using pa to call funcA()..." << endl;pa->funcA();cout << "Using pb to call funcB()..." << endl;pb->funcB();cout << "Using pbc to call funcB()..." << endl;pbc->funcB();cout << endl;cout << "pa = " << pa << endl;cout << "pb = " << pb << endl;cout << "pbe = " << pbe << endl;cout << "pbc = " << pbc << endl;return 0;
}

这里写图片描述

工程开发中的多继承方式:
这里写图片描述

#include <iostream>
#include <string>using namespace std;class Base
{
protected:int mi;
public:Base(int i){mi = i;}int getI(){return mi;}bool equal(Base* obj){return (this == obj);}
};class Interface1
{
public:virtual void add(int i) = 0;virtual void minus(int i) = 0;
};class Interface2
{
public:virtual void multiply(int i) = 0;virtual void divide(int i) = 0;
};class Derived : public Base, public Interface1, public Interface2
{
public:Derived(int i) : Base(i){}void add(int i){mi += i;}void minus(int i){mi -= i;}void multiply(int i){mi *= i;}void divide(int i){if( i != 0 ){mi /= i;}}
};int main()
{Derived d(100);Derived* p = &d;Interface1* pInt1 = &d;Interface2* pInt2 = &d;cout << "p->getI() = " << p->getI() << endl;    // 100pInt1->add(10);pInt2->divide(11);pInt1->minus(5);pInt2->multiply(8);cout << "p->getI() = " << p->getI() << endl;    // 40cout << endl;cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) << endl;cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) << endl;return 0;
}

运行结果:

p->getI() = 100
p->getI() = 40

pInt1 == p : 1
pInt2 == p : 1

一些有用的工程建议:

  1. 先继承自一个父类,然后实现多个接口
  2. 父类中提供equal()成员函数
  3. equal()成员函数用于判断当前指针是否指向当前对象
  4. 与多重继承相关的强制类型转换用dynamic_cast完成

总结:

  1. 多继承中可能出现多个虚函数表指针
  2. 与多重继承相关的强制类型转换用dynamic_cast完成
  3. 工程开发中使用单继承多接口的方式实现多继承
  4. 父类提供成员函数用来判断指针是否指向当前对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zookeeper思维导图

之前用word文档记笔记&#xff0c;但是没有思维导图清晰&#xff0c;又整理了一下&#xff0c;分享一下&#xff1b;

redis 思维导图

之前整理的redis 思维导图&#xff0c;分享一下&#xff0c;后续持续更新;

网站切图初学

先做一个简单的说明为什么选择Photoshop软件而没有选择Firework软件。Friework Dreamweaver Flash号称网页制作三剑客&#xff0c;Friework与Dreamwaver整合得更为紧密&#xff0c;在这里只所以选择photoshop只是因为我的偏好&#xff0c;况且我对 firework软件使用的次数很少&…

main函数的参数的含义

转载自&#xff1a;点击链接 链接2 加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 最近学习服务器网络编程&#xff0c;遇到了一个问题&#xff0c;main函数的参数&#xff0c;特意整理资料记录之&#xff01;&#…

【C++深度剖析教程35】函数模板的概念和意义

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、问题引入&#xff1a; C中有几种变量交换的方法&#xff1f; 定义宏代码块和定义函数 #include <iostream> #include <string>using namespace std;#d…

【C++深度剖析教程36】深入理解函数模板

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、函数模板深入理解 编译器从函数模板通过具体类型产生不同的函数编译器会对函数模板进行两次编译 *对模板进行编译 *对参数替换后的函数进行编译 注意事项&#xf…

【C++深度剖析教程37】类模板的概念和意义

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、类模板 一些类主要用于存储和组织数据元素类中数据的组织方式和数据元素的具体类型无关如 数组类&#xff0c;链表类&#xff0c;stack类&#xff0c;queue类等 C中…

【C++深度剖析教程38】类模板深度剖析

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、多参数类模板 类模板可以定义任意多个不同的类型参数 类模板可以被特化&#xff1a; 指定类模板的特定实现部分类型参数必须显示指定根据类型参数分开实现类模板…

dbeaver 连接hbase 数据库

1.安装dbeaver 参考: https://blog.csdn.net/volitationLong/article/details/80583977 安装dbeaver 2.配置hosts 文件 10.21.21.89 nn01.as 10.21.21.94 nn02.as 10.21.21.93 dn01.as 3.配置用户变量 4. 配置hbase 驱动 连接参数 点击“新建连接”按钮 4.1 选择:a…

docker思维导图

之前学习的总结的思维导图&#xff0c;后续持续更新

ODI配置Mysql5.1数据库服务器

场景&#xff1a;服务器端mysql装了是Mysql5.1版本&#xff0c;最开始使用mysql-connector-java-5.0.6-bin.jar 驱动&#xff0c;经测试&#xff0c;无法连接成功&#xff0c;后来再网络上下载了最新的驱动mysql-connector-java-5.1.12-bin.jar 发现还是没法连接成功。最后面使…

【Linux进程、线程、任务调度】一 Linux进程生命周期 僵尸进程的含义 停止状态与作业控制 内存泄漏的真实含义 task_struct以及task_struct之间的关系

学习交流加&#xff08;可免费帮忙下载CSDN资源&#xff09;&#xff1a;个人微信&#xff1a; liu1126137994学习交流资源分享qq群1&#xff08;已满&#xff09;&#xff1a; 962535112学习交流资源分享qq群2&#xff1a; 780902027 文章目录1、进程控制块PCB2、进程的生命周…

Ubuntu 8.04下Netbeans的字体反锯齿解决(转)

原帖地址&#xff1a;http://www.oklinux.cn/html/Basic/jyjq/20081011/62034.html 测试可用&#xff0c;网上搜的其他方法如复制字体文件等都不成功。 首先说明&#xff0c;我是被锯齿的Netbeans折磨了半年才下决心解决来解决这个问题&#xff0c; 想想还真是冤枉。 我用的Li…

hive工作中分享总结

hive分享总结1. 数据家谱:1.1.Hive 是什么&#xff1f;1.2.数据仓库1.3.Hive与传统数据库的区别1.4.Hive的优缺点1.5.Hive使用场景1.6.Hdfs 运行机制1.7.Mapreduce 运行机制1.8.SQL转化成MapReduce过程1.9.Hive 架构:2.Hive交互方式2.1.Hive交互shell2.2.JDBC交互2.3.第三种交互…

IMX6移植Linux3.0.35内核时需要添加的矩阵按键的平台设备信息

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 本文记录在IMX6开发板上移植鼎芯Linux3.0.35内核时&#xff0c;需要配置的矩阵按键的信息。本设备使用的矩阵按键是一个5*5的矩阵按键。 本人其他开发…

IMX6移植Linux4.1.15内核时需要添加矩阵按键的设备树信息

之前在Linux3.0.35内核移植过按键的信息&#xff0c;请点击链接查看&#xff1a;3.0.35内核移植 本篇文章记录在IMX6开发板移植4.1.15内核时&#xff0c;添加矩阵按键的设备树信息。 1、具体添加的设备树信息 下面是我们的开发板中按键与核心板的引脚链接情况&#xff1a; …

【原创】简单轻松浏览FTP

笔者之前都是用浏览器浏览FTP的&#xff08;笔者用的是360安全浏览器&#xff09;&#xff0c;可后来不知道为什么不能正常浏览了&#xff0c;如下图&#xff1a; 虽然这样也可以下载和浏览FTP上的资源&#xff0c;但总觉得没有像Windows的资源管理器那样来得方便。 上网找了找…

微服务认证解决方案

之前整理的微服务认证文档&#xff0c;分享一下 微服务认证解决方案1.Token认证有两种方式&#xff1a;OAuth2.0&#xff0c;JWT2. oAuth2.0授权方式2.1授权码模式&#xff1a;2.2简化模式:简化模式详细介绍2.3密码模式&#xff1a;密码模式详细介绍2.4客户端模式&#xff1a;2…

I.MX6开发板移植Linux4.1.15内核之TSC2007触摸屏设备树信息的添加

之前写过一篇3.0.35内核移植关于TSC2007触摸屏驱动移植的文章。里面对TSC2007.c驱动程序的分析比较清晰&#xff0c;点击链接查看&#xff1a;点击链接查看 本篇文章&#xff0c;主要记录在4.1.15内核移植的过程中&#xff0c;对于TSC2007设备的添加&#xff0c;需要如何添加设…