virtual base class的问题

本文探讨了虚拟继承在不同编译器(GCC与VS)下的实现差异。通过具体代码实例展示了类对象大小的变化,并深入分析了VS编译器下虚拟继承的具体实现机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    虚拟继承的实现机制在不同的编译器下方法是不同的,因此造成不同编译器下类对象的大小有差异。先上代码:

  8 #include<iostream>
  9 using namespace std;
 10 class A{
 11     public:
 12         virtual void display1(){}
 13     private:
 14        // int x;
 15 };
 16 class B: public virtual A{
 17     public:
 18         virtual void display2(){}
 19 };
 20 
 21 int main() 
 22 {
 23     A a;
 24     B b;
 25     cout << sizeof(a) << endl;
 26     cout << sizeof(b) << endl;
 27     return 0;
 28 }
~      
在Gcc上测试,此时sizeof(a)和sizeof(b)输出都是4。 但是在VS2013上测试,sizeof(a) = 4, sizeof(b) = 12.a的大小为4没问题,即一个虚表指针的大小,在两个编译器上大小相同。但是sizeof(b)的大小在两种编译器上却差距很大。奇怪!再试下在A中定义一个int型数据:

#include<iostream>
using namespace std;

class A{
public:
	virtual void display1(){}
private:
	int x;
};

class B : public virtual A{
public:
	virtual void display2(){}
};

class C : public virtual A{
public:
	virtual void display3(){}
};

class D : public B, public C{
public:
	virtual void display4(){}
};
int main()
{
	A a;
	B b;
	C c;
	D d;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	cout << sizeof(d) << endl;
	system("pause");
	return 0;
}


在Gcc上测试,此时的输出是:sizeof(a)  = 8, sizeof(b) = 12.但是在VS中测试是:sizeof(a) = 8, sizeof(b) = 16,sizeof(c) = 16, sizeof(d = 24)。A中int型数据+虚表指针大小为8,这个也没有问题。但是b的大小还是不同。编译之后,生成如下窗口信息:

>  class A	size(8):
1>  	+---
1>   0	| {vfptr}
1>   4	| x
1>  	+---
1>  
1>  A::$vftable@:
1>  	| &A_meta
1>  	|  0
1>   0	| &A::display1 
1>  
1>  A::display1 this adjustor: 0
1>  
1>  
1>  class B	size(16):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>  	+---
1>  	+--- (virtual base A)
1>   8	| {vfptr}
1>  12	| x
1>  	+---
1>  
1>  B::$vftable@B@:
1>  	| &B_meta
1>  	|  0
1>   0	| &B::display2 
1>  
1>  B::$vbtable@:
1>   0	| -4
1>   1	| 4 (Bd(B+4)A)
1>  
1>  B::$vftable@A@:
1>  	| -8
1>   0	| &A::display1 
1>  
1>  B::display2 this adjustor: 0
1>  
1>  vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>                 A       8       4       4 0
1>  
1>  
1>  class C	size(16):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>  	+---
1>  	+--- (virtual base A)
1>   8	| {vfptr}
1>  12	| x
1>  	+---
1>  
1>  C::$vftable@C@:
1>  	| &C_meta
1>  	|  0
1>   0	| &C::display3 
1>  
1>  C::$vbtable@:
1>   0	| -4
1>   1	| 4 (Cd(C+4)A)
1>  
1>  C::$vftable@A@:
1>  	| -8
1>   0	| &A::display1 
1>  
1>  C::display3 this adjustor: 0
1>  
1>  vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>                 A       8       4       4 0
1>  
1>  
1>  class D	size(24):
1>  	+---
1>  	| +--- (base class B)
1>   0	| | {vfptr}
1>   4	| | {vbptr}
1>  	| +---
1>  	| +--- (base class C)
1>   8	| | {vfptr}
1>  12	| | {vbptr}
1>  	| +---
1>  	+---
1>  	+--- (virtual base A)
1>  16	| {vfptr}
1>  20	| x
1>  	+---
1>  

    让我们来一个个分析:(1)A的起始地址先存放的是vfptr,即虚函数表指针,占4个字节,然后接下来4个字节存放的是数据x,这样a的大小为8;(2)B虚拟继承自A,首先存放的是自己的vfptr,占4字节。然后是指向虚基类的指针vbptr,也是4字节。最后存放类A,占8字节。这样b的大小为16字节;(3)C与B同理,所以c的大小也是16;(4)D共有继承B和C。首先存放B的虚函数表指针和虚基类指针,占8字节。然后是C的虚函数表指针和虚基类指针,占8字节。最后存放A的数据,占8字节。这样一共24字节。

    在VS的实现机制中,虚基类在子类的子类中只有一个实体,子类共享这个实体。子类怎样定位到基类呢?答案就是虚基类指针,指向虚基类的起始地址(我感觉也有可能是偏移值?)。这样在子类的子类及其派生类中永远保证只有一个虚基类的实体。Gcc的实现机制有时间再研究下。






### Base Class in Programming Context In the realm of object-oriented programming (OOP), a **base class**, also referred to as a superclass or parent class, serves as the foundational structure from which other classes derive their properties and methods. This concept allows developers to define relationships between objects by creating hierarchies where derived classes inherit attributes and behaviors defined within the base class[^1]. The naming conventions applied during the creation of these classes play an essential role since they establish terminology used throughout discussions regarding designs. As noted previously, selecting precise terms ensures consistency across all aspects involved when describing such entities within any given system architecture[^3]. For instance, consider implementing inheritance using C++, one would typically start defining what constitutes this primary entity before extending it further through specialized subclasses: ```cpp // Example demonstrating simple inheritance pattern. class Shape { // Base class declaration begins here. public: virtual void draw() const = 0; // Pure Virtual Function Declaration inside shape abstract type definition block ends now. }; class Circle : public Shape { private: double radius; public: explicit Circle(double r):radius(r){} void draw()const override{ std::cout << "Drawing circle with radius:"<<this->getRadius()<<std::endl;} }; ``` This example showcases how `Shape` acts as the foundation upon which specific shapes like circles build additional functionality without needing redundant code replication elsewhere. Additionally, understanding fundamental algorithms related specifically towards managing memory efficiently becomes crucial especially under languages supporting manual control over resources allocation/deallocation processes via destructors etc., thus making knowledge about advanced features indispensable too[^4].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值