c++内存分布之纯虚函数
关于
- 本文演示环境:VS2017+32位程序。
- 纯虚函数是一种特殊的虚函数。可以预测到:虚函数的结论同样适用纯虚函数,但是纯虚函数是一种特殊的存在,还是看看实际结果。
- 代码写的不够规范: 因为任何带虚函数的类的析构函数都应该是虚析构函数。但是我这里没有写出来,目的是缩短文章篇幅。
结论
1.虚函数表指针 和 虚函数表
- 1.1 影响虚函数表指针个数的因素只和派生类的父类个数有关。多一个父类,派生类就多一个虚函数表指针,同时,派生类的虚函数表就额外增加一个
- 1.2 派生类和父类同时含有虚函数,派生类的虚函数按照父类声明的顺序(从左往右),存放在继承的第一个父类中虚函数表后面,而不是单独再额外建立一张虚函数表
- 1.3 按照
先声明、先存储、先父类、再子类
的顺序存放类的成员变量 - 1.4 无论是派生类还是父类,当出现了虚函数(普通虚函数、虚析构函数、纯虚函数),排在内存布局最前面的一定是虚函数表指针
2.覆盖继承
其实,覆盖继承不够准确。
2.1 成员变量覆盖
- 派生类和父类出现了同名的成员变量时,派生类仅仅将父类的同名成员隐藏了,而非覆盖替换
- 派生类调用成员变量时,按照就近原则,调用自身的同名变量,解决了当调用同名变量时出现的二义性的现象
2.2 成员函数覆盖
需要考虑是否有虚函数的情况
存在虚函数的覆盖继承
父类和派生类出现了同名虚函数函数((普通虚函数、纯虚函数),派生类的虚函数表中将子类的同名虚函数的地址替换为自身的同名虚函数的地址-------多态出现
不存在虚函数的覆盖继承
父类和派生类同时出现同名成员函数,这与成员变量覆盖继承的情况是一样的,派生类屏蔽父类的同名函数
1.单一继承
1.1 基类仅含有一个纯虚函数
1.1.1 代码
class baseD
{
public:
virtual void jumping() = 0;
int _mz = 100;
};
// 派生类
class deriveA : public baseD
{
public:
int _me = 3;
int _mf = 4;
};
1.1.2 内存分布
1>class deriveA size(16):
1> +---
1> 0 | +--- (base class baseD)
1> 0 | | {vfptr}
1> 4 | | _mz
1> | +---
1> 8 | _me
1>12 | _mf
1> +---
1>
1>deriveA::$vftable@:
1> | &deriveA_meta
1> | 0
1> 0 | &baseD::jumping
- 果然,与单一继承中基类只有一个虚函数的情况是完全一致的。
1.2 基类增加到2个纯虚函数
1.2.1 代码
class baseD
{
public:
virtual void jumping() = 0;
virtual void turning() = 0;
int _mz = 100;
};
// 派生类
class deriveA : public baseD
{
public:
int _me = 3;
int _mf = 4;
};
1.2.2 内存分布
1>class deriveA size(16):
1> +---
1> 0 | +--- (base class baseD)
1> 0 | | {vfptr}
1> 4 | | _mz
1> | +---
1> 8 | _me
1>12 | _mf
1> +---
1>
1>deriveA::$vftable@:
1> | &deriveA_meta
1> | 0
1> 0 | &baseD::jumping
1> 1 | &baseD::turning
- 分布情况与上面1.1中内存分布一致。