当前位置: 首页 > news >正文

第五十四课、被遗弃的多重继承(下)

一、多继承产生的问题三:可能产生多个虚函数表

 

#include<iostream>

using namespace std;

class BaseA
{
public:    
    virtual void func()
    {
        cout << "BaseA::func()" << endl;
    }
};

class BaseB
{
public:
    virtual void func()
    {
        cout << "BaseB::func()" << endl;
    }
};

class Derived : public BaseA, public BaseB
{
};                
int main()
{

    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;//8==>两个指向虚函数表的指针

    Derived d;
    BaseA *pa = &d;
    BaseB *pb = &d;

    pa->func();//BaseA::func()
    pb->func();//BaseB::func()    
    cout << "pa = " << pa << endl;//pa = 0xbfb3b368
    cout << "pb = " << pb << endl;//pb = 0xbfb3b36c, 比pa的地址大4,正好是一个指针的大小
    
    cout << endl;
 
    BaseB* pbb = (BaseB *)(pa);//暴力强制类型转换,不会修改指针的值
    pbb->func();//期望BaseB::func(),实际BaseA::func()
    cout << "pbb = " << pbb << endl;//期望与pb的地址相同,实际与pa的地址相同

    cout << endl;

    BaseB* pbbb = dynamic_cast<BaseB*>(pa);//编译器先从对象d的地址得到这个对象,然后从前对象树树上找到BaseB,并且修改指针的值到BaseB
    pbbb->func();//期望BaseB::func(),实际上也是
    cout << "pbbb = " << pbbb << endl;//期望与pb的地址相同,实际也是

    return 0;
}

//输出结果
/*
sizeof(Derived) = 8
BaseA::func()
BaseB::func()
pa = 0xbfb3b368
pb = 0xbfb3b36c

BaseA::func()
pbb = 0xbfb3b368

BaseB::func()
pbbb = 0xbfb3b36c
*/

二、正确使用多重继承:一些工程的建议

(1)、先继承自一个父类,然后实现多个多个接口

(2)、父类中提供equal()成员函数

(3)、equal()成员函数用于判断指针是否指向当前对象

(4)、与多重继承相关的强制类型转换用dynamic_cast完成

#include <iostream>

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); } }; //接口1 class Interface1 { public: virtual void add(int i) = 0; virtual void minus(int i) = 0; }; //接口2 class Interface2 { public: virtual void multiply(int i) = 0; virtual void divide(int i) = 0; }; //看起来虽然很像多继承,但除了Base类外,其它的都是接口 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; // 100; pInt1->add(10); //i == 110; pInt2->divide(11); //i == 110 / 11 pInt1->minus(5); //i = 10 - 5; pInt2->multiply(8); //i = 5 * 8; cout << "p->getI() = " << p->getI() << endl; //40 cout << endl; //注意,通过dynamic_cast将pInt1和pInt2指针转为指向d对象中Base对子对象部分, //这样尽管pInt1和pInt2的值不同,但他们都转为同一个Base指针,然后通过Base类的 //equal函数,判断转换后的两个指针是否相等,从而可以判断他们是不是指向同一个 //对象d。
  //这样就解决了多重继承多个地址的问题
cout << "pInt1 == p: " <<p->equal(dynamic_cast<Base*>(pInt1)) << endl; //1 cout << "pInt2 == p: " <<p->equal(dynamic_cast<Base*>(pInt2)) << endl; //1 return 0; } //输出结果 /*
p->getI() = 100 p->getI() = 40 pInt1 == p: 1 pInt2 == p: 1
*/

三、小结

(1)、多继承可能出现多个虚函数表指针

(2)、与多继承相关的强制类型转换用dynamic_cast完成

(3)、工程开发中使用单继承多接口的方式使用多继承

(4)、父类提供equal()成员函数用于判断指针是否指向当前对象

 

转载于:https://www.cnblogs.com/gui-lin/p/6370714.html

相关文章:

  • 拖拽div大小
  • 4xx错误的本质:服务器已经接收到请求
  • sql server 查询表结构
  • Swift 中异常抛出和四种异常处理
  • JDK Tools and Utilities---Java Troubleshooting, Profiling, Monitoring and Management Tools
  • Sagit.Framework For IOS 开发框架入门开发教程2:一行代码实现引导页
  • 简单实现UIlabel可复制功能
  • 大数据学习系列之五 ----- Hive整合HBase图文详解
  • REST开放接口生成文档工具之apidoc
  • 自建Maven仓库 - Artifactory
  • 微信管理
  • 推荐一个提升工作效率的小插件[intellij-postfix-templates]
  • 面试(1)
  • ios - 关于拖动手势简单应用场景
  • 第二课、GUI程序实例分析------------------狄泰软件学院
  • [NodeJS] 关于Buffer
  • canvas绘制圆角头像
  • js
  • k8s如何管理Pod
  • Magento 1.x 中文订单打印乱码
  • Netty 4.1 源代码学习:线程模型
  • Rancher如何对接Ceph-RBD块存储
  • React16时代,该用什么姿势写 React ?
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • sublime配置文件
  • vue-loader 源码解析系列之 selector
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 反思总结然后整装待发
  • 计算机常识 - 收藏集 - 掘金
  • 讲清楚之javascript作用域
  • 警报:线上事故之CountDownLatch的威力
  • 那些被忽略的 JavaScript 数组方法细节
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 什么是Javascript函数节流?
  • 小程序01:wepy框架整合iview webapp UI
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • - 转 Ext2.0 form使用实例
  • Java性能优化之JVM GC(垃圾回收机制)
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • #define、const、typedef的差别
  • $.proxy和$.extend
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (4)Elastix图像配准:3D图像
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)【Hibernate总结系列】使用举例
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .net 反编译_.net反编译的相关问题