C++ 虚拟继承问题

文章目录

    • 前言
    • 为什么要有虚拟继承
    • 虚拟继承和普通继承的区别
    • 虚拟继承 sizeof() 问题

前言

本篇文章主要描述虚拟继承中内存分布情况,当然,可能会不太完全正确,希望大家多多指正

为什么要有虚拟继承

我们看下面一种情景:

class A
{
public:
	int a;
};

class B : public A
{
public:
	int b;
};

class C : public A
{
public :
	int C;
};

class D : public B, public C
{
public:
	void func()
	{
		
	}
};

为了更加方便理解,用图表示:
C++ 虚拟继承问题_第1张图片
如上图,那么就会出现问题:类D中的成员变量 int a,如果访问a,就会出现二义性问题,到底是B中的a,还是C中的A,并且会造成数据冗余问题。

其中,对于二义性问题,我们加访问限定即可。例如 C::a;但对于数据冗余问题却没有办法解决。

于是C++中就引入了虚拟继承

将代码改为:

class A
{
public:
	int a;
};

class B : virtual public A
{
public:
	int b;
};

class C : virtual public A
{
public :
	int C;
};

class D : public B, public C
{
public:
	void func()
	{
		
	}
};

如果,类中带有虚函数。内存结构会变为怎样??

class A
{
public:
	A(int v = 100) :X(v) {};

	virtual void foo(void) {}

	int X;

};

class B :virtual public A
{
public:
	B(int v = 10) :Y(v), A(100) {};

	virtual void fooB(void) {}

	int Y;

};

class C : virtual public A
{
public:
	C(int v = 20) :Z(v), A(100) {}

	virtual void fooC(void) {}

	int Z;

};

class D : public B, public C
{
	D(int v = 40) :B(10), C(20), A(100), L(v) {}

	virtual void fooD(void) {}

	int L;

};

C++ 虚拟继承问题_第2张图片
对于类A,内存布局:
C++ 虚拟继承问题_第3张图片
对于类B,内存布局:
C++ 虚拟继承问题_第4张图片
对于类D,内存布局:
C++ 虚拟继承问题_第5张图片

虚拟继承和普通继承的区别

class A
{
public:
	virtual void funA();
};  

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

class A
{
public:
	virtual void funA();
};  

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

上述两种继承有什么区别??一种普通继承,一种虚拟继承

首先,我们知道,如果一个类中有虚函数,那么就会有一个虚表,有一个指针指向这个虚表。
对于A,内存布局如下:
C++ 虚拟继承问题_第6张图片
对于普通继承,继承的虚函数和本有的虚函数共用同一个虚表
则普通继承 B布局如下:
C++ 虚拟继承问题_第7张图片

但对于虚拟继承来说,不管是基类还是派生类都需要有一个指针来维护自己的虚表,并且还要有一个指针指向虚基表,其中存放偏移量
C++ 虚拟继承问题_第8张图片

虚拟继承 sizeof() 问题

有了上面的基础,来看几道题:

//第一种情况
class a         
{            
    virtual void func();
};           
class b:public virtual a
{            
    virtual void foo(); 
};           

//第二种情况
class a           
{              
    virtual void func();
 };             
 class b :public a     
{              
     virtual void foo(); 
 };                         

//第三种情况
class a         
{            
   virtual void func();
   char x;       
};            
class b:public virtual a 
{          
	virtual void foo();
};            

//第四种情况
 class a
 {
   virtual void func()
    char x;
  };
 class b:public a
 {
   virtual void foo();
 };

对于每种情况,分别计算 sizeof(a), sizeof(b)的大小
结果:
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8

参照上述普通继承和虚拟继承的区别,就知道原因了。

你可能感兴趣的:(C++)