概述
一、类成员函数
class test
{
public:
void myfunc(){}
virtual void vfunc() {}
static void sfunc() {}
};
void myfunc(){}
查看上述代码的可执行文件的符号清单
可见,所有的成员函数最终在可执行文件中,都被转化成了具有唯一函数名的成员函数,所以,类的成员函数经过编译器处理后,实质上就是全局函数
非static成员函数的转换过程主要就是添加this指针参数并用this指针访问类数据成员,最后改写函数名,将函数变为一个含有this指针的全局函数。类中的成员变量也会在编译期被添加上类名以保证成员名的唯一性。
此外,类中的静态成员函数与普通成员函数最大的区别就是没有隐式实参this,正因为没有this指针,所以不能调用非访问非static成员和调用非static成员函数,也不能被const修饰。static成员函数的地址在编译期就已经确定,因此不能使用virtual修饰
二、反汇编虚析构函数
再说一下析构函数的执行过程
1、析构函数的函数体先被执行。2、1执行完后,逆序销毁类对象中的显示成员变量。3、2执行完后,如果类对象中含有vptr,那么vptr将会被重置。4、3执行完后,如果该类含有基类,那么也会调用基类部分的析构函数,顺序同1,2,3。54执行完后,如果该类含有虚基类,那么也会调用虚基类部分的析构函数,顺序同1,2,3。
在https://blog.csdn.net/Master_Cui/article/details/109957302曾提到,基类的析构函数一般都是虚函数,但是通过多态调用到子类的虚析构函数后,基类的析构函数是如何被调用的?
class base
{
public:
base() {}
~base() {}
};
class derive:public base
{
public:
derive() {}
~derive() {}
};
int main()
{
base *bp=new derive();
delete bp;
return 0;
}
其中,derive的析构函数对应的汇编代码如下
所以,在derive的析构函数中,编译器自动安插了基类base的析构函数的调用代码,所以,基类base析构函数的调用是由编译器来完成的
将上述代码改为多重继承
class base
{
public:
base() {}
virtual ~base() {}
};
class base2
{
public:
base2() {}
virtual ~base2() {}
};
class derive:public base, public base2
{
public:
derive() {}
~derive() {}
};
derive的析构函数的汇编代码如下
三、RTTI
RTTI的基本内容见https://blog.csdn.net/Master_Cui/article/details/110520918
通过前面的文章已经知道,RTTI信息的地址存在vtbl中,所以,如果一个类中没有虚函数,那么就没有所谓的RTTI信息。
例如,Base1的RTTI的信息结构如下
四、多态的开销
4.1、继承深度增加,效率的开销一般也会增加
比如下面的代码
class A
{
public:
A() {
cout << "A::A()" << endl;
}
};
class B :public A{};
class C : public B
{
public:
C(){
cout << "C::C()" << endl;
}
};
当创建一个C对象时,首相要调用A和B的构造函数,开销增加,多重继承同理
4.2、增加虚函数,开销也会相应的增大
因为虚函数的支持需要vtbl、vptr,这就需要额外的内存开销,此外,需要在对象的构造函数中给vptr赋值,这也增加了效率的开销。多重继承和虚继承的vptr比单一继承多,内存的开销也会相应的增大,而且,二者还需要this指针的调整,效率也会有所降低。虚继承还需要VTT以及construction vtable,内存的开销也会变大。
所以,继承,虚函数,多重继承以及虚继承的使用有可能会对程序的性能有一定的影响
参考
《深度探索C++对象模型》
《C++新经典:对象模型》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出
最后
以上就是高高冷风为你收集整理的C++对象模型7——类的成员函数、反汇编虚析构函数、RTTI、多态的开销的全部内容,希望文章能够帮你解决C++对象模型7——类的成员函数、反汇编虚析构函数、RTTI、多态的开销所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复