第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;
}

原文地址:https://www.cnblogs.com/-glb/p/11967935.html

时间: 2024-10-11 11:47:01

第53课 被遗弃的多重继承 (中)的相关文章

第53课 被遗弃的多重继承(上)

1. 单一继承 (1)实验代码 #include <iostream> #include <string> using namespace std; void visitVtbl(int **vtbl) { cout << vtbl << endl; cout << "\t[-1]: " << (long)vtbl[-1] << endl; typedef void (*FuncPtr)(); int

第53课 被遗弃的多重继承

问题:C++中是否允许一个类继承自多个父类呢?答案是肯定的,这种现象就是多重继承多重继承是C++中一个特有的特性,因为在其他的程序设计语言里面,如C#.java等语言只支持单重继承 C++支持编写多重继承的代码-一个子类可以拥有多个父类-子类拥有所有父类的成员变量-子类继承所有父类的成员函数-子类对象可以当作任意父类对象使用 多重继承的语法规则 class Derived: public BaseA, public BaseB, public BaseC { // .... }; 多重继承的本质

第53课 被遗弃的多重继承 (下)——正确的使用多重继承

工程开发中的多重继承方式:(这是面向对象理论中所推荐的方式)单继承某个类 + 实现(多个)接口 #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);

第54课 被遗弃的多重继承(下)

1. C++中的多重继承 (1)一个子类可以拥有多个父类 (2)子类拥有所有父类的成员变量 (3)子类继承所有父类的成员函数 (4)子类对象可以当作任意父类对象使用 (5)多重继承的语法规则 class Derived: public BaseA, public BaseB, public BaseC{…}; 2. 多重继承问题一 (1)通过多重继承得到的对象可以拥有“不同的地址”!!! (2)解释方案:无 (3)原因分析 [编程实验]多重继承问题一 #include <iostream> u

C++--被遗弃的多重继承、经典问题

一.被遗弃的多重继承 Q:C++中是否允许一个类继承自多个父类?在实际的C++编译环境中,C++是支持编写多重继承的代码1.一个子类可以拥有多个父类2.子类拥有所有父类的成员变量3.子类继承所有父类的成员函数4.子类对象可以当作任意父类对象使用多重继承的语法规则但是在多重继承中会存在许多问题Q:多重继承得到的对象可能拥有不同的地址代码示例 #include <iostream> #include <string> using namespace std; class BaseA {

c++学习笔记5,多重继承中派生类的构造函数与析构函数的调用顺序(二)

现在来测试一下在多重继承,虚继承,MI继承中虚继承中构造函数的调用情况. 先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace std; class base { public: base() { cout<<"base created!"<<endl; }

智慧解析第08课:《战国策》中的心理学

智慧解析第08课:<战国策>中的心理学,布布扣,bubuko.com

Spark IMF传奇行动第21课:从Spark架构中透视Job

版权声明:本文为博主原创文章,未经博主允许不得转载.作者:HaiziS 昨晚听了王家林老师的Spark IMF传奇行动第21课:从Spark架构中透视Job,笔记如下: 默认一个worker有一个executor,也可以设置多个,当cpu利用不足时. 并行度也是被继承的 当Spark集群启动的时候,首先启动Master进程负责整个集群资源管理和分配并接受作业的提交且为作业分配计算资源,每个工作节点默认启动一个Worker Process来管理当前节点的mem,cpu等计算资源并且向Master汇

第五十三课、被遗弃的多重继承(上)

一.c++的多重继承 1.c++支持编写多重继承的代码 (1).一个子类可以拥有多个父类 (2).子类拥有所有父类的成员变量 (3).子类继承所有父类的成员函数 (4).子类对象可以当做任意父类对象使用 2.多重继承产生的问题一:通过多重继承得到的对象拥有不同的地址 #include<iostream> using namespace std; class BaseA { protected: int ma; public: BaseA(int a) { ma = a; } int GetA(