【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;

管理软件本质论

我们上管理软件到底是为了什么&#xff1f;1 为员工提供自动化工具&#xff0c;可以让他们节省出更多的时间可以做更多的工作&#xff1f;2 可以通过管理软件的互联网联网特性或局域网联网特性&#xff0c;让部门和部门之间、总部和分公司之间按业务流程通常运营&#xff1f;2 …

【C++深度剖析教程32】new/malloc区别 delete/free区别

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、new与malloc的区别&#xff1a; new是关键字&#xff0c;它是C语言的一部分&#xff0c;而malloc是由C库提供的函数new分配的内存的单位是具体的类型大小&#xff0c…

redis 思维导图

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

软件汉化教程

看到网上经常有人问汉化方面的东西&#xff0c;我今天也来灌水一篇&#xff0c;来个汉化扫盲教程。写的不好的地方欢迎大家指正&#xff01;OK&#xff0c;现在我们进入正题。我这里所说的汉化&#xff0c;是指汉化 Windows 下的 PE 文件&#xff0c;把其他语言界面的程序翻译为…

图的DFS深度遍历

最近复习了一下图的内容&#xff0c;记录一下&#xff0c;后续添加详解&#xff08;无向图的深度遍历&#xff09; package com.qey.learn;import java.util.ArrayList; import java.util.Arrays;/*** ClassName graph* Description* Author qianxl* Date 2021-03-06 17:18* V…

【C++深度剖析教程33】C++中的构造函数与析构函数是否可以为虚函数

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 问题一&#xff1a;构造函数与析构函数可以成为虚函数么&#xff1f; 答案&#xff1a; 1、构造函数不可以成为虚函数 因为在构造函数执行结束后&#xff0c;虚函数表…

网站切图初学

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

【C++深度剖析教程34】C++中的强制类型转换dynamic_cast

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; C中的继承中&#xff0c;如何使用强制类型转换&#xff1f; 知识点&#xff1a; dynamic_cast是与继承相关的类型转换关键字dynamic_cast要求相关的类中必须有虚函数dy…

main函数的参数的含义

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

C#FTP操作

C# FTP操作类 收藏 using System;using System.Collections;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;using System.Text.RegularExpressions; namespace Discuz.Common{ /// <summary> /// FTP类 /// </summary> …

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

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

生产者和消费者

注意&#xff01;&#xff01; notify和wait 使用后续补充 package com.qey.learn;/*** ClassName Water* Description* Author qianxl* Date 2021-03-01 23:09* Version 1.1**/ public class Water {// 服务员来提供产品的输入的输出private int product;public Water(int m…

前端学习(133):雪碧图实现原理

百度词条对雪碧图的解释是&#xff1a;CSS雪碧 即CSS Sprite&#xff0c;也有人叫它CSS精灵&#xff0c;是一种CSS图像合并技术&#xff0c;该方法是将小图标和背景图像合并到一张图片上&#xff0c;然后利用css的背景定位来显示需要显示的图片部分。 举个应用的实例&#xff…

如何在C++中动态分配二维数组

一般是三种方法&#xff1a;(1)用vector的vector&#xff0c;(2)先分配一个指针 数组&#xff0c;然后让里面每一个指针再指向一个数组&#xff0c;这个做法的好处是访问数组元素时比较直观&#xff0c;可以用a[x][y]这样的写法&#xff0c;缺点是它相当于C#中的一个锯齿 数组&…

循环打印ABA问题

注意&#xff01;&#xff01; notify 虚拟锁问题&#xff0c;后续补充 package com.qey.learn;/*** ClassName SwapPrint* Description* Author qianxl* Date 2021-03-02 14:46* Version 1.1**/ public class SwapPrint {public int flag 0;public synchronized void prin…

【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中…

链表中求倒数第几个元素并打印出来

//补充一下 链表的逆序操作 添加到listed 类中public Listed reverse() {Listed head this;Listed p head;// 单个节点的情况if (p.next null) {return p;}// 从第二节点的开始Listed q p;p p.next;q.next null;// 防止自循环// 临界条件while (p ! null) {Listed temp…