[C++基础]对象内存分布--虚继承

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ouyangshima/article/details/88825455

virtual在C++中最大的功能就是声明虚函数和虚基类。虚拟继承是为了解决多重继承下公共基类的多份拷贝问题。

虚继承

虚继承解决了菱形继承中对派生类拥有多个间接父类实例的情况。虚继承的派生类的内存布局与普通继承很多不同,主要体现在:

  1. 虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个虚函数指针(vptr)以及一张虚函数表。该vptr位于对象内存最前面。vs非虚继承:直接扩展父类虚函数表。
  2. 虚继承的子类也单独保留了父类的vprt与虚函数表。这部分内容接与子类内容以一个四字节的0来分界。
  3. 虚继承的子类对象中,含有四字节的虚表指针偏移值

虚基类表解析

在C++对象模型中,虚继承而来的子类会生成一个隐藏的虚基类指针(vbptr),在MicrosoftVisualC++中,虚基类表指针总是在虚函数表指针之后,因而,对某个类实例来说,如果它有虚基类指针,那么虚基类指针可能在实例的0字节偏移处(该类没有vptr时,vbptr就处于类实例内存布局的最前面,否则vptr处于类实例内存布局的最前面),也可能在类实例的4字节偏移处。
一个类的虚基类指针指向的虚基类表,与虚函数表一样,虚基类表也由多个条目组成,条目中存放的是偏移值。第一个条目存放虚基类表指针(vbptr)所在地址到该类内存首地址的偏移值,由第一段的分析我们知道,这个偏移值为0(类没有vptr)或者-4(类有虚函数,此时有vptr)。我们通过一张图来更好地理解。


虚基类表的第二、第三...个条目依次为该类的最左虚继承父类、次左虚继承父类...的内存地址相对于虚基类表指针的偏移值,这点我们在下面会验证。

单虚拟继承

class Base
{
public:
	virtual void fun1()
	{
		cout << "Base::func1()" << endl;
	}
	virtual void fun2()
	{
		cout << "Base::func2()" << endl;
	}
private:
	int b;
};
class Derive : virtual public Base
{
public:
	virtual void fun1()
	{
		cout << "Derive::func1()" << endl;
	}
	virtual void fun3()
	{
		cout << "Derive::func3()" << endl;
	}
	void fun4()
	{
		cout << "Derive::func4()" << endl;
	}
private:
	int d;
};
//1 > class Derive	size(20) :
//1 > +-- -
//1 > 0 | {vfptr}
//1 > 4 | {vbptr}
//1 > 8 | d
//1 > +-- -
//1 > +-- - (virtual base Base)
//1 > 12 | {vfptr}
//1 > 16 | b
//1 > +-- -
//1 >
//1 > Derive::$vftable@Derive@:
//1 > | &Derive_meta
//1 > | 0
//1 > 0 | &Derive::fun3
//1 >
//1 > Derive::$vbtable@:
//1 > 0 | -4
//1 > 1 | 8 (Derived(Derive + 4)Base)
//1 >
//1 > Derive::$vftable@Base@:
//1 > | -12
//1 > 0 | &Derive::fun1
//1 > 1 | &Base::fun2
//1 >
//1 > Derive::fun1 this adjustor: 12
//1 > Derive::fun3 this adjustor: 0
//1 > vbi: class  offset o.vbptr  o.vbte fVtorDisp
//1 >       Base      12       4       4 0
//1 >

多虚拟继承

class Base1 
{
public:
	virtual void fun1()
	{
		cout << "Base1::fun1" << endl;
	}
	virtual void fun2()
	{
		cout << "Base1::fun2" << endl;
	}
private:
	int b1;
};
class Base2
{
public:
	virtual void fun1()
	{
		cout << "Base2::fun1" << endl;
	}
	virtual void fun2()
	{
		cout << "Base2::fun2" << endl;
	}
private:
	int b2;
};
class DeriveA : virtual public Base1, virtual public Base2
{
public:
	virtual void fun1()
	{
		cout << "DeriveA::fun1" << endl;
	}
	virtual void fun3()
	{
		cout << "DeriveA::fun3" << endl;
	}
private:
	int d1;
};
//1 > class DeriveA	size(28) :
//1 > +-- -
//1 > 0 | {vfptr}
//1 > 4 | {vbptr}
//1 > 8 | d1
//1 > +-- -
//1 > +-- - (virtual base Base1)
//1 > 12 | {vfptr}
//1 > 16 | b1
//1 > +-- -
//1 > +-- - (virtual base Base2)
//1 > 20 | {vfptr}
//1 > 24 | b2
//1 > +-- -
//1 >
//1 > DeriveA::$vftable@DeriveA@:
//1 > | &DeriveA_meta
//1 > | 0
//1 > 0 | &DeriveA::fun3
//1 >
//1 > DeriveA::$vbtable@:
//1 > 0 | -4
//1 > 1 | 8 (DeriveAd(DeriveA + 4)Base1)
//1 > 2 | 16 (DeriveAd(DeriveA + 4)Base2)
//1 >
//1 > DeriveA::$vftable@Base1@:
//1 > | -12
//1 > 0 | &DeriveA::fun1
//1 > 1 | &Base1::fun2
//1 >
//1 > DeriveA::$vftable@Base2@:
//1 > | -20
//1 > 0 | &thunk: this -= 8; goto DeriveA::fun1
//1 > 1 | &Base2::fun2
//1 >
//1 > DeriveA::fun1 this adjustor: 12
//1 > DeriveA::fun3 this adjustor: 0
//1 > vbi:  class  offset o.vbptr  o.vbte fVtorDisp
//1 >       Base1      12       4       4 0
//1 >       Base2      20       4       8 0
//1 >

菱形虚拟继承

class Base
{
public:
	virtual void func1()
	{
		cout << "Base::func1()" << endl;
	}
	virtual void func2()
	{
		cout << "Base::func2()" << endl;
	}
private:
	int b;
};
class Base1 : virtual public Base
{
public:
	virtual void func1()
	{
		cout << "Base1::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Base1::func3()" << endl;
	}
private:
	int b1;
};
class Base2 :virtual public Base
{
public:
	virtual void func1()
	{
		cout << "Base2::func2()" << endl;
	}
	virtual void func4()
	{
		cout << "Base2::func4()" << endl;
	}
private:
	int b2;
};
class Derive : virtual public Base1, virtual public Base2
{
public:
	virtual void func1()
	{
		cout << "Derive::func1()" << endl;
	}
	virtual void func5()
	{
		cout << "Derive::func5()" << endl;
	}
private:
	int d;
};
//1 > class Derive	size(44) :
//1 > +-- -
//1 > 0 | {vfptr}
//1 > 4 | {vbptr}
//1 > 8 | d
//1 > +-- -
//1 > +-- - (virtual base Base)
//1 > 12 | {vfptr}
//1 > 16 | b
//1 > +-- -
//1 > +-- - (virtual base Base1)
//1 > 20 | {vfptr}
//1 > 24 | {vbptr}
//1 > 28 | b1
//1 > +-- -
//1 > +-- - (virtual base Base2)
//1 > 32 | {vfptr}
//1 > 36 | {vbptr}
//1 > 40 | b2
//1 > +-- -
//1 >
//1 > Derive::$vftable@:
//1 > | &Derive_meta
//1 > | 0
//1 > 0 | &Derive::func5
//1 >
//1 > Derive::$vbtable@Derive@:
//1 > 0 | -4
//1 > 1 | 8 (Derived(Derive + 4)Base)
//1 > 2 | 16 (Derived(Derive + 4)Base1)
//1 > 3 | 28 (Derived(Derive + 4)Base2)
//1 >
//1 > Derive::$vftable@Base@:
//1 > | -12
//1 > 0 | &Derive::func1
//1 > 1 | &Base::func2
//1 >
//1 > Derive::$vftable@Base1@:
//1 > | -20
//1 > 0 | &Base1::func3
//1 >
//1 > Derive::$vbtable@Base1@:
//1 > 0 | -4
//1 > 1 | -12 (Derived(Base1 + 4)Base)
//1 >
//1 > Derive::$vftable@Base2@:
//1 > | -32
//1 > 0 | &Base2::func4
//1 >
//1 > Derive::$vbtable@Base2@:
//1 > 0 | -4
//1 > 1 | -24 (Derived(Base2 + 4)Base)
//1 >
//1 > Derive::func1 this adjustor: 12
//1 > Derive::func5 this adjustor: 0
//1 > vbi:  class  offset o.vbptr  o.vbte fVtorDisp
//1 >        Base      12       4       4 0
//1 >       Base1      20       4       8 0
//1 >       Base2      32       4      12 0
//1 >

 

展开阅读全文

没有更多推荐了,返回首页