欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 【C++ 第十章】继承:在单继承和多继承的情况下,子类中分别含有多少个虚表?

【C++ 第十章】继承:在单继承和多继承的情况下,子类中分别含有多少个虚表?

2024/11/17 13:31:07 来源:https://blog.csdn.net/2301_79499548/article/details/141473845  浏览:    关键词:【C++ 第十章】继承:在单继承和多继承的情况下,子类中分别含有多少个虚表?

总结放在前面:

继承体系中就是有几个父类就有几张虚表

单继承只有一张虚表,继承下来的父类的虚表被用做子类的虚表了(或者说 继承的父类和子类共用一块虚表空间,父类的虚函数写在前面,子类的在后面)

多继承是有多少个父类就有多少虚表,其中第一个父类的虚表被用做子类的虚表的(原理和上面单继承的一样)

其中,子类新增的虚函数放在第一张虚表后面(即子类的虚表后面)

分四种情况演示:↓

下面我将使用程序打印 子类中虚表的内容:包括虚表本身的地址 与 虚表中各个虚函数的地址

目的是为了观察 子类的虚表中,父类的虚表和子类的虚表相对存储位置

声明:

1、我下面程序实在 32位系统下,指针大小为 4 位,因此直接将对象地址强转成 int* ,使其获取 前 4 个字节的数据(即一个int大小),虚函数表地址一般放在一个对象存储空间的开头,这4个字节直接就获取到 虚表地址了

2、关于为什么要定义函数指针及其使用介绍:因为虚函数表,是一个 函数指针 数组,因此要定义函数指针来取 该数组的元素,又因为该数组名就是该数组的首地址,指针的指针就是 (FunPtr*)

1.单继承无虚函数覆盖:

// 父类
class Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func2(){cout << "Base::Func2" << endl;}};// 子类
class Derive :public Base
{
public:virtual void Func3(){cout << "Derive::Func3" << endl;}virtual void Func4(){cout << "Derive::Func4" << endl;}
};typedef void(*FunPtr)();   // 定义函数 void Fuc() 的函数指针 :函数类型 void ()(....形参列表),函数指针位置在函数名的位置,void (  *p  )(....形参列表)
//打印虚函数表
void PrintVF(FunPtr* VFaddress)
{cout << "虚表地址:" << VFaddress << endl;int i = 1;FunPtr vfunc = VFaddress[0];while (vfunc != nullptr){cout << "第 " << i << " 个虚函数地址:" << vfunc << endl;vfunc();cout << '\n';VFaddress++;vfunc = *VFaddress;i++;}cout << "\n\n";
}int main()
{Base b;Derive d;cout << "父类虚表:" << "\n\n";PrintVF((FunPtr*)*(int*)&b);  // *(int*)&b :将对象b的头4个字节的数据取出,这就是对象 b 的虚表地址// 将虚表地址强转成函数指针类型 FunPtr*cout << "子类虚表:" << endl;PrintVF((FunPtr*)*(int*)&d);system("pause");return 0;
}

在对象的存储中,虚表指针地址在存储空间的开头

单继承时,子类中只有一个虚函数表,父类虚函数在前,子类虚函数在后,按照声明顺序存放。

子类和父类共用同一张虚表,父类指向这张虚表的开头,子类虚表指针也指向这张虚表开头

只是 父子类虚表指针可以访问的范围不同,父子类都被准许访问自己区域的数据


2.单继承有虚函数覆盖

// 父类
class Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func2(){cout << "Base::Func2" << endl;}};// 子类
class Derive :public Base
{
public:virtual void Func1(){cout << "Derive::Func1" << endl;}virtual void Func2(){cout << "Derive::Func2" << endl;}
};typedef void(*FunPtr)();   // 定义函数 void Fuc() 的函数指针 :函数类型 void ()(....形参列表),函数指针位置在函数名的位置,void (  *p  )(....形参列表)
//打印虚函数表
void PrintVF(FunPtr* VFaddress)
{cout << "虚表地址:" << VFaddress << endl;int i = 1;FunPtr vfunc = VFaddress[0];while (vfunc != nullptr){cout << "第 " << i << " 个虚函数地址:" << vfunc << endl;vfunc();cout << '\n';VFaddress++;vfunc = *VFaddress;i++;}cout << "\n\n";
}int main()
{Base b;Derive d;cout << "父类虚表:" << "\n\n";PrintVF((FunPtr*)*(int*)&b);  // *(int*)&b :将对象b的头4个字节的数据取出,这就是对象 b 的虚表地址// 将虚表地址强转成函数指针类型 FunPtr*cout << "子类虚表:" << endl;PrintVF((FunPtr*)*(int*)&d);system("pause");return 0;
}


子类中有一个虚函数表,覆盖的虚函数放在虚函数表中继承于父类的位置,新增的虚函数放在继承的父类虚表的后面。(即 重写的虚函数 直接放到继承的父类虚表 后面,共用同块空间)


3.多继承没有虚函数重写:

多继承时,子类中虚表个数等于直接父类的个数,子类中新增的虚函数放在第一个父类虚表末尾,按照声明顺序存放。

class Base1
{
public:virtual void Func1(){cout << "Base1::Func1" << endl;}virtual void Func2(){cout << "Base1::Func2" << endl;}};class Base2
{
public:virtual void Func1(){cout << "Base2::Func1" << endl;}virtual void Func2(){cout << "Base2::Func2" << endl;}};class Derive :public Base1, Base2
{
public:virtual void Func3(){cout << "Derive::Func3" << endl;}virtual void Func4(){cout << "Derive::Func4" << endl;}};typedef void(*FucPtr)();
void PrintVF(FucPtr* VFaddress)
{cout << "虚表地址:" << VFaddress << endl;int i = 1;FucPtr vfunc = VFaddress[0];while (vfunc != nullptr){cout << "第" << i << "个虚函数地址:" << vfunc << endl;vfunc();VFaddress++;vfunc = *VFaddress;i++;}cout << '\n';
}int main()
{Base1 b1;Base2 b2;Derive d;cout << "父类虚表(Base1):" << endl;PrintVF((FucPtr*)*(int*)&b1);cout << "父类虚表(Base2):" << endl;PrintVF((FucPtr*)*(int*)&b2);cout << "Derive ::Base1:" << endl;PrintVF((FucPtr*)*(int*)&d);cout << "Derive ::Base2:" << endl;PrintVF((FucPtr*)(*(int*)((char*)&d + sizeof(Base1))));system("pause");return 0;
}

4.多继承有虚函数重写时

多继承有虚函数重写时,子类中虚表个数等于直接父类的个数,子类中重写的虚函数覆盖继承的父类的虚函数,子类中新增的虚函数放在第一个直接父类的虚表末尾,按照声明顺序存放

参考文章:

c++中的虚函数及虚函数表

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com