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

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

 

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

 

posted @ 2017-02-06 15:59  lgc202  阅读(266)  评论(0编辑  收藏  举报