💯 博客内容:多态
😀 作 者:陈大大陈
🚀 个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!
💖 欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信 😘 😘 😘
目录
普通菱形继承
虚表指针偏移
菱形虚继承的情况
普通菱形继承
class Base1 {
public:virtual void func1() { cout << "Base1::func1" << endl; }virtual void func2() { cout << "Base1::func2" << endl; }
private:int b1;
};class Base2 {
public:virtual void func1() { cout << "Base2::func1" << endl; }virtual void func2() { cout << "Base2::func2" << endl; }
private:int b2;
};class Derive : public Base1, public Base2 {
public:virtual void func1() { cout << "Derive::func1" << endl;}virtual void func3() { cout << "Derive::func3" << endl; }
private:int d1;
};int main()
{Derive d;return 0;
}
上面这种多继承的情况,Derive有几个虚表呢?
答案是,因为继承了Base1和Base2两个类,所以有两个虚表。
但是这样的话,就会衍生出一个问题,它自己的虚函数也就是func3放在哪里呢?
我没看到,编译器仍旧是故技重施,欺骗我们的眼睛,我们检测监测不到func3。
我们打印一下第一张虚表,这很容易想到。
class Base1 {
public:virtual void func1() { cout << "Base1::func1" << endl; }virtual void func2() { cout << "Base1::func2" << endl; }
private:int b1;
};class Base2 {
public:virtual void func1() { cout << "Base2::func1" << endl; }virtual void func2() { cout << "Base2::func2" << endl; }
private:int b2;
};class Derive : public Base1, public Base2 {
public:virtual void func1() { cout << "Derive::func1" << endl;}virtual void func3() { cout << "Derive::func3" << endl; }
private:int d1;
};int main()
{Derive d;//打印第一张虚表PrintVFT((VFUNC*)(*(int*)&d));return 0;
}
虚表指针偏移
那么,怎么打印第二张虚表呢?
PrintVFT((VFUNC*)(*(int*)((char*)&d+sizeof(Base1))));
这么打印,需要注意的是,d是一个Derive类,加一的话会加上一个Derive的大小。
所以这里必须把它强制类型转换成char*。
其实也可以这么打印。
PrintVFT((VFUNC*)(*(int*)((Base1*)&d+1)));
结果是一样的。
还可以这样写,最聪明的一种写法。
Base2* ptr = &d;PrintVFT((VFUNC*)(*(int*)ptr));
Base2指针会自己切割,便宜到Base2那里。
我们得到结论,func3放到了第一个虚表里面。
菱形虚继承的情况
class A
{
public:virtual void func1() { cout << "A::func1" << endl;}
public:int _a;
};class B : public A
{
public:virtual void func1(){cout << "B::func1" << endl;}virtual void func3(){cout << "B::func3" << endl;}public:int _b;
};class C : public A
{
public:virtual void func1(){cout << "C::func1" << endl;}virtual void func5(){cout << "C::func5" << endl;}
public:int _c;
};class D : public B, public C
{
public:virtual void func1(){cout << "D::func1" << endl;}virtual void func2(){cout << "D::func2" << endl;}
public:int _d = 1;
};int main()
{D d;return 0;
}
先来看一个问题,D里有几张虚表?
答案是两张,这种情况就跟普通的多继承没两样。
改成虚拟菱形继承就不一样了。
此时有看起来有3个虚表,其实还是2个。菱形这块太复杂,我不分析了。