深度探索C++对象内存模型

前面简单的论述过C++对象模型,总觉得不够深入,现近闲来进一步挖掘C++对象内存布局情况。主要讨论:单一继承,多重继承,钻石继承的有无虚函数以及虚拟继承的情况。贴出测试程序,并给出测试结论以及对应的类对象的大小计算。(PS:类对象的内存布局取决于编译器,这里的测试都是基于Visual Studio)

单一的类对象

单一的类对象主要考虑有虚函数的情况,前面提及的博文已有介绍,类中定义了虚函数,就会产生一个虚函数表(实质就是一个函数指针数组,虚函数表不在类中,VS编译环境下,虚函数表位于常量段,虚表指针在类对象中),类每定义一个对象,便会在对象的最前面安插一个虚表指针,指向虚函数表,这样该类定义的对象会多出4 Byte(32位)。

可以在Visual Studio C++ 编译输出中直接看C++内存布局:工程项目——右键“属性”——配置属性——C/C++——命令行——其他选项里添加“/d1reportAllClassLayout ”,即可在编译输出中查看定义的类的内存布局,上面是输出所有定义的类对象,你可以搜索你自己定义的对象。(最好不要把名字定为base,不然一大堆)。

using namespace std;

class parent
{
//public:
	int b;
    static int a;
	virtual void fun1()
	{
		cout << "parent: fun1" << endl;
	}
	/*virtual void fun2()
	{
		cout << "parent: fun2" << endl;
	}*/
};

int main()
{
	parent obj_b;
	
	return 0;
}
下面便是定义的类对象内存布局情况:vfptr 即表示虚表指针,static 成员不在类对象中
1>  class parent	size(8):
1>  	+---
1>   0	| {vfptr}
1>   4	| b
1>  	+---

如果类中不定义为虚函数,类对象的大小是4,如下:
1>  class parent	size(4):
1>  	+---
1>   0	| b
1>  	+---
下面我们来考虑类继承的情况:

单一继承

1)一般继承,无虚函数

1.1 继承一个基类

class parent
{
//public:
	int b;
	/*virtual void fun1()
	{
		cout << "parent: fun1" << endl;
	}*/
};

class child: public parent
{
	int a;
};

int main()
{
	child obj_b;
	
	return 0;
}
内存布局:
1>  class child	size(8):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | b
1>  	| +---
1>   4	| a
1>  	+---

1.2 再考虑继承两个基类的情况

class parent
{
//public:
	int b;
	/*virtual void fun1()
	{
		cout << "parent: fun1" << endl;
	}*/
};

class parent1
{
	int c;
};

class child: public parent, public parent1
{
	int a;
};

int main()
{
	child obj_b;
	
	return 0;
}
内存布局:
1>  class child	size(12):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | b
1>  	| +---
1>  	| +--- (base class parent1)
1>   4	| | c
1>  	| +---
1>   8	| a
1>  	+---

可以看出,一般继承无虚函数的情况下,派生类对象的内存布局为,先存放基类成员,再存放自身成员变量,其大小是简单的基类对象大小与自身成员大小之和。继承多个基类时,数据成员按继承声明的前后顺序放置。

2)存在虚函数的情况

2.1 基类定义虚函数,派生类本身无虚函数

class parent
{
//public:
	int b;
	virtual void fun1()
	{
		cout << "parent: fun1" << endl;
	}
};

class parent1
{
	int c;
};

class child: public parent/*, public parent1*/
{
	int a;
};

int main()
{
	child obj_b;
	return 0;
}
内存布局:
1>  class child	size(12):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | {vfptr}
1>   4	| | b
1>  	| +---
1>   8	| a
1>  	+---
这个和上面的一般继承没啥区别,只不过是基类中定义了虚表指针,然后被派生类一股脑继承下来

2.2 继承多个基类

class parent
{
	int b;
	virtual void fun1()
	{
		cout << "parent: fun1" << endl;
	}
};

class parent1
{
	int c;
	virtual void fun2()
	{
		cout << "parent1" << endl;
	}
};

class child: public parent, public parent1
{
	int a;
};

int main()
{
	child obj_b;
	
	return 0;
}
内存布局
1>  class child	size(20):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | {vfptr}
1>   4	| | b
1>  	| +---
1>  	| +--- (base class parent1)
1>   8	| | {vfptr}
1>  12	| | c
1>  	| +---
1>  16	| a
1>  	+---

可以看到,继承多个基类也和无虚函数的情况一样,这里和继承单个的区别在于,派生类会产生两个虚表指针,后面我们会用程序验证,这两个虚表指针指向不同的两个虚函数表,可以顺便总结一下,非虚继承下,派生类继承几个含有虚函数的基类,那么派生类的实例对象就会有几个虚表指针。

2.3 含虚函数情况

1.基类无虚函数,派生类自身定义有虚函数

class parent
{
public:
	int b;
	/*virtual void fun2()
	{
		cout << "parent" << endl;
	}*/
};

class child: public parent
{
public:
	int a;
	virtual void fun2()
	{
		cout << "child" << endl;
	}
};

int main()
{
	return 0;
}

内存布局

1>  class child	size(12):
1>  	+---
1>   0	| {vfptr}
1>  	| +--- (base class parent)
1>   4	| | b
1>  	| +---
1>   8	| a
1>  	+---

可以看出,虚表指针总是放在对象的最前面,哪怕它是定义在派生类中。

基类有虚函数,派生类无虚函数,这个简单,不赘述了

2.当基类,派生类自身都定义虚函数的情况

class parent
{
public:
	int b;
	virtual void fun2()
	{
		cout << "parent" << endl;
	}
};

class child: public parent
{
public:
	int a;
	virtual void fun1()
	{
		cout << "child" << endl;
	}
};

int main()
{
	return 0;
}
内存布局:

1>  class child	size(12):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | {vfptr}
1>   4	| | b
1>  	| +---
1>   8	| a
1>  	+---

这个一开始以为派生类也会占据一个自身虚表指针空间的,一看发现错了。细看布局,你会发现子类对象中虚表指针是继承的父类对象的,那么子类对象本身就不会产生虚函数指针么?答案是肯定的。那么子类对象的虚函数指针在哪呢?位于同一个虚函数表中。下面我们通过程序验证一下。

typedef void(*fun)(void);
int main()
{
	child obj;

	fun pFun = NULL;
	pFun = (fun)*((int*)*(int*)(&obj));
	pFun();

	pFun = (fun)*((int*)*(int*)(&obj)+1);
	pFun();

	return 0;
}
output:
parent
child
上面的语句 pFun = (fun)*((int*)*(int*)(&obj)); 前面说过虚函数表实质是一个函数指针数组,数组里面存放的是虚函数指针。对象中只存放指向虚函数表的虚表指针,并且位于对象的最前面,也就是说虚表指针与对象是同一个地址。回过头看这条程序:(int*)(&obj) 对对象地址也就是虚表指针(虚函数表的地址)强制转换,(int*)*(int*)(&obj) 解引用虚表指针,定位到了虚函数表(函数指针数组),这指向了数组(首位置)。(fun)*((int*)*(int*)(&obj)) 有了前面这个就好理解了,取数组首元素得到虚函数指针,然后强制转换。

从上面的测试输出可以看出,这种情况下派生类对象中只有一个虚表指针,派生类的虚函数指针位于同一个虚函数表中,且位于基类虚函数指针的后面。

1>  child::$vftable@:
1>  	| &child_meta
1>  	|  0
1>   0	| &parent::fun2 
1>   1	| &child::fun1 
如果派生类中的虚函数名为fun2,自然的就同名覆盖了基类的。

2.3 多重继承情况

1)继承多个基类

class parent
{
public:
	int a;
	virtual void fun_p()
	{
		cout << "parent" << endl;
	}
};

class adopter
{
public:
	int b;
	virtual void fun_a()
	{
		cout << "adopter" << endl;
	}
};
class child : public parent, public adopter
{
public:
	int c;
	virtual void fun_c()
	{
		cout << "child" << endl;
	}
};

int main()
{
	return 0;
}

内存布局:

1>  class child	size(20):
1>  	+---
1>  	| +--- (base class parent)
1>   0	| | {vfptr}
1>   4	| | a
1>  	| +---
1>  	| +--- (base class adopter)
1>   8	| | {vfptr}
1>  12	| | b
1>  	| +---
1>  16	| c
1>  	+---

由于两个基类都有虚函数,这样继承下来,子类对象便会有两个虚表指针,也就是说子类会有两个虚函数表。子类对象中的虚函数指针是存放在继承的第一个父类的虚函数表中

1>  child::$vftable@parent@:
1>  	| &child_meta
1>  	|  0
1>   0	| &parent::fun_p 
1>   1	| &child::fun_c 
1>  
1>  child::$vftable@adopter@:
1>  	| -8
1>   0	| &adopter::fun_a 

那如果父类中只有一个有虚函数呢?

class parent
{
public:
	int a;
	/*virtual*/ void fun_p()
	{
		cout << "parent" << endl;
	}
};

class adopter
{
public:
	int b;
	virtual void fun_a()
	{
		cout << "adopter" << endl;
	}
};
class child : public parent, public adopter
{
public:
	int c;
	virtual void fun_c()
	{
		cout << "child" << endl;
	}
};
内存布局
1>  class child	size(16):
1>  	+---
1>  	| +--- (base class adopter)
1>   0	| | {vfptr}
1>   4	| | b
1>  	| +---
1>  	| +--- (base class parent)
1>   8	| | a
1>  	| +---
1>  12	| c
1>  	+---
这里故意不在第一个父类定义虚函数,看内存布局会发现,父类adopter处于子类对象的最前面,因为它定义有虚函数,Visual Studio 编译器保证了虚表指针位于对象最前面的原则,这样如果继承的多个父类均有虚函数,那么存放位置根据继承顺序来,如果有个没有定义虚函数,则不管继承的顺序,均按照虚函数优先原则来,有虚函数的放置在最前面。

2)累积继承

class parent
{
	int a;
	virtual void fun_p()
	{
		cout << "parent" << endl;
	}
};

class child : public parent
{
	int b;
	virtual void fun_c()
	{
		cout << "child" << endl;
	}
};

class grandchild : public child
{
	int c;
	virtual void fun_g()
	{
		cout << "grandchild" << endl;
	}
};

int main()
{
	grandchild obj_b;

	return 0;
}

//内存布局
1>  class grandchild	size(16) :
1>  	+-- -
1> | +-- - (base class child)
1> | | +-- - (base class parent)
1>   0 | | | {vfptr}
1>   4 | | | a
1> | | +-- -
1>   8 | | b
1> | +-- -
1>  12 | c
1>  	+-- -

//虚函数表
1>  grandchild::$vftable@:
1> | &grandchild_meta
1> | 0
1>   0 | &parent::fun_p
1>   1 | &child::fun_c
1>   2 | &grandchild::fun_g
从上面看,以及综合前面基类中含有虚函数的情况可以看出,子类对象中的虚表指针取决于继承的定义有虚函数的父类的个数(非虚拟继承),当然如果父类没有虚函数那就取决于本身有没有虚函数了。如果上面的这个子类(应该叫孙类),再继承parent,那么它会多一个虚表指针。而子类若自身也定义虚函数,则它不会产生虚表指针(继承的父类有虚表指针的情况下),而是把它的虚函数指针放置在继承的父类的虚函数表中,这是出于利用虚函数实现多态的目的,这里我们主要讨论内存布局情况,虚函数继承与多态,后面再说。

在介绍钻石型继承前,我们再考虑上面论述的其中几种情况的虚拟继承下的类对象的内存布局:

虚拟继承(虚基类)

我们就以上面的这个累积继承为例并扩展,阐述一下虚拟继承是如何影响类对象内存布局的

class parent
{
	int a;
	virtual void fun_p()
	{
		cout << "parent" << endl;
	}
};

class child :virtual public parent
{
	int b;
	virtual void fun_c()
	{
		cout << "child" << endl;
	}
};

class grandchild :virtual public child
{
	int c;
	virtual void fun_g()
	{
		cout << "grandchild" << endl;
	}
};
一看内存布局,可不是发生了一点点的微秒变化
1>  class child	size(20):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>   8	| b
1>  	+---
1>  	+--- (virtual base parent)
1>  12	| {vfptr}
1>  16	| a
1>  	+---

1>  class grandchild	size(32):
1>  	+---
1>   0	| {vfptr}
1>   4	| {vbptr}
1>   8	| c
1>  	+---
1>  	+--- (virtual base parent)
1>  12	| {vfptr}
1>  16	| a
1>  	+---
1>  	+--- (virtual base child)
1>  20	| {vfptr}
1>  24	| {vbptr}
1>  28	| b
1>  	+---
先看类child,对比2.3.2,一般继承,基类派生类均含虚函数的情况(sizeof(child_obj) = 12),这里虚拟继承,瞬间多了8 Byte,

首先虚拟继承,子类对象中自然会多出一个虚基类指针vbptr,但虚表指针还是在对象的最前面,还有一个最大的改变就是子类会产生两个虚函数表,这样实例化的对象便会有两个虚表指针,这颠覆了前面得出的结论,不能简单的按继承的含虚函数的父类的个数来判定了。

这里阐述的情况是虚拟继承的情况,对于前面子类含虚表指针个数与含虚函数父类个数的关系限于非虚拟继承情况下。对于虚拟继承,可以看出,它是全盘继承某个子类。

可以看出,

1>  child::$vftable@child@:
1>  	| &child_meta
1>  	|  0
1>   0	| &child::fun_c 
1>  
1>  child::$vbtable@:
1>   0	| -4
1>   1	| 8 (childd(child+4)parent)
1>  
1>  child::$vftable@parent@:
1>  	| -12
1>   0	| &parent::fun_p 
中间是虚基类指针。上面两个虚表指针指向不同的两个虚函数表,我们可以通过程序验证一下:
typedef void(*fun)(void);
int main()
{
	child obj;

	fun pFun = NULL;
	pFun = (fun)*((int*)*(int*)(&obj));
	pFun();

	pFun = (fun)*((int*)*((int*)(&obj)+3));
	pFun();

	return 0;
}

//output
child
parent
对于上面的指针,注意与前面提到的相区别:虚函数表的地址位移和对象内的地址位移。

3、钻石型继承

所谓钻石型继承就是继承方式形如下面的“菱形”结构

     A
    / \
   B   C
    \ /
	    D

下面演示这样一种情况:

class class_A
{
public:
	int a;
	void fun_a()
	{
		cout << "a" << endl;
	}
};

class class_B : public class_A
{
public:
	int b;
	void fun_b()
	{
		cout << "b" << endl;
	}
};

class class_C : public class_A
{
public:
	int c;
	void fun_c()
	{
		cout << "c" << endl;
	}
};

class class_D : public class_B, public class_C
{
public:
	int d;
	void fun_d()
	{
		cout << "d" << endl;
	}
};

int main()
{
	class_D obj;
	return 0;
}
内存布局如下
1>  class class_D	size(20):
1>  	+---
1>  	| +--- (base class class_B)
1>  	| | +--- (base class class_A)
1>   0	| | | a
1>  	| | +---
1>   4	| | b
1>  	| +---
1>  	| +--- (base class class_C)
1>  	| | +--- (base class class_A)
1>   8	| | | a
1>  	| | +---
1>  12	| | c
1>  	| +---
1>  16	| d
1>  	+---

上面的程序有问题,从内存布局就可以看出,如果调用基类成员a,就会产生二义性,究竟是调用哪个,因为BC内部都继承有A的成员变量,最后的子类对象都有a的两份拷贝。这时候虚基类就横空出世了,前面有讲到虚拟继承。如果上面采用虚继承,那么最后的子类D的实例只会拥有一个,看下面

class class_A
{
public:
	int a;
	virtual void fun_a()
	{
		cout << "a" << endl;
	}
};

class class_B : virtual public class_A
{
public:
	int b;
	virtual void fun_b()
	{
		cout << "b" << endl;
	}
};

class class_C : virtual public class_A
{
public:
	int c;
	virtual void fun_c()
	{
		cout << "c" << endl;
	}
};

class class_D : public class_B, public class_C
{
public:
	int d;
	virtual void fun_d()
	{
		cout << "d" << endl;
	}
};

int main()
{
	class_D obj;
	return 0;
}

看内存布局前,先分析下这个派生类class_D的实例会占用多少内存。按照前面总结的来,class_D 非虚继承两个含有虚函数的基类,那么其对象中便会有两个虚表指针(自身的虚函数指针就放在第一个虚函数表中),一股脑继承下来,并且自身不会产生虚表指针。可以直接看继承的class_B,虚继承A,那么class_B就会占用12 Bytes(虚表指针,虚基类指针以及int成员变量),同理 class_C也会占用12 Bytes(虚继承自身也会产生多余的虚表指针),再考虑共继承的A,本身会有虚表指针,然后成员变量会放在派生类的最后,A的成员只会在派生类D中存在一份拷贝(* bytes),这是虚基类的目的,避免二义性,然后class_D,由于是一般继承,自身就是int 型4 Byte。总的下来就是 12+12+8+4 = 36 Bytes。

1>  class class_D	size(36):
1>  	+---
1>  	| +--- (base class class_B)
1>   0	| | {vfptr}
1>   4	| | {vbptr}
1>   8	| | b
1>  	| +---
1>  	| +--- (base class class_C)
1>  12	| | {vfptr}
1>  16	| | {vbptr}
1>  20	| | c
1>  	| +---
1>  24	| d
1>  	+---
1>  	+--- (virtual base class_A)
1>  28	| {vfptr}
1>  32	| a
1>  	+---
如果把最后的class_D 也虚继承 B和C(两个都虚继承才行),那么最后的大小会是多少呢?虚继承首先会多出虚基类指针,然后自身也会多余产生一个虚表指针,那么会多出8Bytes,最后的大小就是44 Bytes,挺大的。
如果只是class_D 只是虚继承其中一个基类,好吧,表示已经凌乱了,在Visual Studio 下,虽然大小不会改变,不会多出虚表指针和虚基类指针,但是内存布局却改变了,

代码不贴了,直接看内存布局也会知道继承关系:

1>  class class_D	size(36):
1>  	+---
1>  	| +--- (base class class_C)
1>   0	| | {vfptr}
1>   4	| | {vbptr}
1>   8	| | c
1>  	| +---
1>  12	| d
1>  	+---
1>  	+--- (virtual base class_A)
1>  16	| {vfptr}
1>  20	| a
1>  	+---
1>  	+--- (virtual base class_B)
1>  24	| {vfptr}
1>  28	| {vbptr}
1>  32	| b
1>  	+---
结合前面的虚继承内存布局会发现,虚继承的东西都是放在后面。进一步深究就没意义了。

下面的程序告诉你,虚表指针不一定总是在对象的最前面:

class class_A
{
public:
	int a;
	virtual void fun_a()
	{
		cout << "a" << endl;
	}
};

class class_B: virtual public class_A
{
public:
	int b;
	void fun_b()
	{
		cout << "b" << endl;
	}
};

typedef void(*fun)(void);

int main()
{
	class_B obj;
	fun pFun = NULL;
	pFun = (fun)*((int*)*((int*)(&obj)+2));
	pFun();

	return 0;
}

//内存布局
1>  class class_B	size(16) :
1>  	+-- -
1>   0 | {vbptr}
1>   4 | b
1>  	+-- -
1>  	+-- - (virtual base class_A)
1>   8 | {vfptr}
1 > 12 | a
1 > +-- -


前面啰嗦了一大片,我们可以得出以下几点:

  1. 一般继承下(无虚函数),派生类的内存布局是先放基类成员,多个基类的按继承的顺序放置,最后是派生类自身的成员变量,函数和static变量不在类对象中。这样派生类对象的大小便是继承的基类的大小与自身变量的大小之和。
  2. 一般继承下(含虚函数),与上面的区别就是考虑虚表指针了。1、派生类只继承一个基类的情况下,不管是基类定义有虚函数还是派生类本身有虚函数,或是两个都有虚函数,最后的派生类对象中只会有一个虚表指针,并且是位于对象的最前面。两个都有虚函数的话,派生类的虚函数指针会存放在虚函数表(数组)中基类的虚函数指针的后面。2、当派生类继承多个基类时,如果多个基类中只有一个基类有虚函数,那就和前面的一样。多个基类都有虚函数,那么派生类对象就会产生多个虚表指针,虚表指针的个数与继承的含虚函数的基类的个数一样,派生类的虚函数指针放在第一个虚函数表中。
  3. 虚继承下(有虚函数),虚继承除了多出一个虚基类指针外,整个对象的内存布局也会随之改变。只要是虚继承,那么对应的派生类就会产生一个虚基类指针。另外只要是虚继承,那么基类会并且只会在派生类对象中存在一份拷贝,并且虚继承的东西是放在后面,哪怕它带有虚表指针(虚表指针不一定都是在对象的最前面)。进一步总结虚继承下的虚表指针情况,由于虚继承,派生类会存在基类的一份完整拷贝,这样派生类会产生多余的自身的虚表指针。

计算类对象大小的时候,考虑以上几点便很容易得出。附带一句,上面的测试和总结都是基于Visual Studio 编译器。



  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《深度探索C++对象模型》是由侯捷所著的一本经典的C++图书,该书于2012年由机械工业出版社出版。本书的主要内容涵盖了C++对象模型的深入解析和探讨。 在书中,作者详细讲解了C++中的对象模型和相关的概念,如类、对象、继承、多态等。作者首先介绍了C++对象模型的基本概念和特点,包括对象内存布局、虚函数表和虚函数指针等。然后,作者深入探讨了C++中的继承机制和多态性,包括单继承、多继承、虚继承等。作者还详细介绍了虚函数的实现原理和使用方法。 在书中,作者对C++对象模型的实现细节进行了深入的剖析,包括成员变量和成员函数的内存布局、函数指针和成员函数指针的用法等。同时,作者还讨论了C++中的一些高级特性,如模板、内存管理和异常处理等。通过对C++对象模型深度探索,读者可以更好地理解C++的内部机制和原理,提高程序设计和开发能力。 《深度探索C++对象模型》适合具有一定的C++编程基础的读者阅读,尤其是对C++对象模型感兴趣的读者。通过阅读本书,读者可以进一步了解C++的底层实现和运行机制,从而提高自己的编程能力和代码质量。此外,本书还提供了大量的示例代码和实践案例,可以帮助读者更好地理解和应用所学知识。 总之,《深度探索C++对象模型》是一本深入探讨C++对象模型的经典著作,通过对C++的底层实现和内部机制的剖析,帮助读者深入理解C++编程语言,并提高自己的软件开发能力。 ### 回答2: 《深度探索C++对象模型》是由Stanley B. Lippman于1994年所著的一本经典畅销的C++书籍,该书详细介绍了C++对象模型的内部实现细节。 C++对象模型是指C++编译器在处理对象、继承、多态等面向对象特性时所采用的具体实现方式。这本书通过对对象模型的剖析,帮助读者深入理解C++的内部工作原理,从而写出更高效、更可靠的C++代码。 在《深度探索C++对象模型》中,作者首先介绍了对象、虚函数、继承等C++核心概念,然后详细讲解了C++对象模型的构建过程,包括对象布局、成员函数指针、虚函数表等。作者逐步深入地剖析了C++对象模型内存中的表示方式,解释了为什么C++可以支持如此强大的面向对象特性。 此外,本书还探讨了一些高级主题,如多重继承、虚拟继承、构造函数和析构函数的执行顺序等。对于想要深入学习C++的读者来说,这本书提供了一些宝贵的技术手册和实用的经验。 尽管《深度探索C++对象模型》的出版时间是1994年,但它仍然被广泛认可为学习C++对象模型的经典之作。在2012年时,由于C++的发展和演进,也许一些内容已经有些过时,但很多基本概念和原理仍然适用。 总而言之,《深度探索C++对象模型》是一本值得阅读的C++经典著作,通过深度探索C++对象模型,读者可以更加深入地了解C++的内部工作原理和实现方式,提升自己的开发技能。 ### 回答3: 《深度探索C++对象模型》是一本于2012年出版的书籍。该书的作者Andrews和Sorkin以全面的角度深入探讨了C++对象模型。该书重点介绍了C++中的对象表示、虚函数、继承、多重继承、构造函数、析构函数等内容,以及与之相关的语法、原理和底层实现。 这本书为读者揭示了C++对象模型的奥秘,让人更加深入地理解C++语言中的类和对象。作者通过分析对象布局、虚函数表、虚函数调用、多继承中的数据布局和函数调用等等,解释了C++对象模型的实现机制。 在读者了解C++对象模型的基础上,该书还介绍了如何有效地利用对象模型来提高程序的性能。作者讨论了虚函数的成本以及如何减少虚函数调用的开销,提供了一些优化技巧。此外,书中还对C++的构造函数和析构函数进行了深入的讨论,详细解释了构造函数和析构函数的执行机制和注意事项。 总的来说,《深度探索C++对象模型》是一本深入剖析C++对象模型的重要参考书籍。通过阅读该书,读者可以更加全面地了解C++的类和对象的实现原理,对于理解C++语言的底层机制和优化程序性能具有积极的作用。无论是对于初学者还是有一定C++基础的开发人员来说,该书都是一本值得阅读的重要参考书。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值