zoukankan      html  css  js  c++  java
  • 第53课 被遗弃的多重继承 (中)

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

    #include <iostream>
    
    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;
        cout << "sizeof(d)=" << sizeof(d) <<endl;
    
        return 0;
    }

    sizeof(d) = 8

    相关的三个类中都没有定义成员变量,那这8个字节是从哪来的,谁占用的?
    虚函数表指针

    在Derived这个类中有两个成员,这两个成员都是虚函数表指针。在创建对象的时候,这两个成员会指向不同的虚函数表

    #include <iostream>
    
    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* pbb = (BaseB*)pa;
    
        cout<< "using pa to call funcA()..." <<endl;
        pa->funcA();  //对funcA的调用肯定是通过指向虚函数表的指针来完成的
    
        cout << "using pb to call funcB()..." << endl;
        pb->funcB()     //对funcA的调用肯定是通过指向虚函数表的指针来完成的
        cout<< "using pbb to call funcB()..." << endl; pbb->funcB(); //这个地方应该打印funcB(),而打印结果是funcA()

    return 0;
    }

    需要进行强制类型转换时,C++中推荐使用新式类型转换关键字。
    解决方案:dynamic_cast

    通过pa指针调用funcA的过程:
    从pa中得到对象的地址;
    通过该地址找到虚函数表指针;
    通过虚函数表的指针到虚函数表中去找对应的函数地址。
    因此找到的是funcA的地址。

    通过pb调用funcB的过程与pa调用funcA的过程是一样的。

    通过pbb指针调用funcB的过程:
    首先通过pbb得到对象的地址;
    然后去找虚函数表指针,找到的虚函数表是vptr1;
    去vptr1这个虚函数指针所指的虚函数表中找funcB的地址,在这个地方肯定找不到。找到的是funcA的地址。

    原因:原因就是(BaseB* )pa这个地方的强制类型转换是有问题的。在进行强制类型转换时,推荐使用新式类型转换关键字,不要再使用C语言那种暴力的强制转换了

    int main()
    {
        Derived d;
        BaseA* pa = &d;
        BaseB* pb = &d;
        BaseB* pbb = dynamic_cast<BaseB*>(pa);
    
        cout<< "using pa to call funcA()..." <<endl;
        pa->funcA();
    
        cout << "using pb to call funcB()..." << endl;
        pb->funcB();
    
        cout<< "using pbb to call funcB()..." << endl;
        pbb->funcB();
    
        return 0;
    }

    BaseB* pbb = dynamic_cast<BaseB*>(pa);
    此时编译器做了什么呢?
    由于使用了dynamic_cast这个关键字,编译器就会去做检查,首先编译器就会检查pa这个对象所指向的对象是什么,发现是d对象。
    进而编译器会去看d对象它有哪些父类呢?发现有BaseA和BaseB,然后编译器就会认为这个地方进行的强制类型转换是合法的,那又会怎样呢?编译器在强制类型转换的时候就会对指针有一个修正的过程。使得pbb指向pb所指的位置。

    int main()
    {
        Derived d;
        BaseA* pa = &d;
        BaseB* pb = &d;
        BaseB* pbb = dynamic_cast<BaseB*>(pa);
        BaseB* pbc = (BaseB*)pa;
    
        cout<< "using pa to call funcA()..." <<endl;
        pa->funcA();
    
        cout << "using pb to call funcB()..." << endl;
        pb->funcB();
    
        cout<< "using pbb to call funcB()..." << endl;
        pbb->funcB();
    
        cout << "pa=" << pa <<endl;
        cout << "pb=" << pb << endl;
        cout << "pbb=" << pbb << endl;
        cout << "pbc=" << pbc << endl;
    
        return 0;
    }



  • 相关阅读:
    【LeetCode】Validate Binary Search Tree
    【LeetCode】Search in Rotated Sorted Array II(转)
    【LeetCode】Search in Rotated Sorted Array
    【LeetCode】Set Matrix Zeroes
    【LeetCode】Sqrt(x) (转载)
    【LeetCode】Integer to Roman
    贪心算法
    【LeetCode】Best Time to Buy and Sell Stock III
    【LeetCode】Best Time to Buy and Sell Stock II
    CentOS 6 上安装 pip、setuptools
  • 原文地址:https://www.cnblogs.com/-glb/p/11967935.html
Copyright © 2011-2022 走看看