之前学习的一些总结

C++多态的实现

C++多态就是在基类的函数前面加上virtual关键字,然后在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。用起来就是这么简单顺手,现在要剖析一下是怎么实现的了。

C++中,一个类存在虚函数,那么编译器就会为这个类生成一个虚函数表,在虚函数表里存放的是这个类所有虚函数的入口地址。

那么虚函数表存在哪里呢?类仅仅是一个“蓝图”,没有实际的存储空间。如果考虑到内存四区模型,应该会存放在只读数据段,因为虚函数表是由编译器自动添加的,所以也只有放在这个地方才合适。

所以如果一个类中包含了虚函数,那么编译器在编译的时候,会在这个类对象的前面4个字节加上一个指针变量,指向虚函数表的入口地址,根本不考虑到底是用父类指针还是子类指针来接管这个对象。

也就是说,对于父类和子类,都有自己的虚函数表,在赋值语句右边进行创建对象的时候,就绑定了对应的对象的虚函数的入口地址,那么以后调用对象的时候,如果调用的是虚函数,就只能从虚函数表中找到对应函数的执行入口地址。

问题来了,虚函数表是编译器在编译阶段就创建好的,那么那个创建对象的前面的虚函数指针是什么时候初始化的呢?

应该是在构造函数中进行初始化,在构造子类对象的时候,要先调用父类的构造函数,此时编译器只能看到父类,并不能察觉到子类的存在,它初始化父类对象的vptr,该虚函数指针指向父类的虚函数表,当执行子类构造函数的时候,子类对象的vptr指针被初始化,指向自身的虚函数表。

还有一点要说的是,在继承体系中,如果子类重写了父类中的虚函数,父类子类中的虚函数在虚函数表中的位置是一样的,这就涉及到了编译器如何安排布局虚函数的位置了。

猜你喜欢

转载自www.cnblogs.com/randyniu/p/9244321.html