zoukankan      html  css  js  c++  java
  • 第五十四课、被遗弃的多重继承(下)

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

    #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()成员函数用于判断指针是否指向当前对象

  • 相关阅读:
    linux虚拟机时间同步
    jdk的下载
    xshell 使用命令上传、下载文件
    linux常用命令
    linux使用"userdel 用户名“删除用户的解决办法
    List去重
    C#之数据类型学习
    EF中使用SQL语句或存储过程
    牛逼注释
    ASP.NET判断是否为手机登录
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6370714.html
Copyright © 2011-2022 走看看