2020/08/04在华为面试过程中被问到:“虚函数的实现原理是什么?”,那一刻我懵了,在面试结束后,我查询了一下相关的文章,发现我曾经看过这个知识点,只不过长时间不使用,已经忘记了,现在重新查资料再记录一遍。
一.虚函数的实现原理:
1.c++虚函数这个概念设置的目的是什么?
我看了一些博客简单的思考是:为了代码重用,其实就是c++类的多态性的体现,和模板函数应该也是有相似的目的性吧
这里就不在详细的去解释了,可以看文章虚函数的设计目的。
2.实现原理
不少博客中都解释了,C++通过虚函数表和虚函数表指针来实现virtual function机制,具体而言:
- 对于一个class,会产生一堆指向虚函数的指针,这些指针被统一放在一个表格中,这个表格被称为虚函数表,英文又称做virtual table(vtbl)。
- 每实例化一个对象时,都会系统内添加一个指针,这个指针指向的是这个类的虚函数表,通常这个指针被称作虚函数表指针(vptr)。出于效率的考虑,该指针通常放在对象实例最前面的位置。
通过上面的讲述,大概清楚了其实现的原理了,那么举例子来进一步讲解:
class BaseClass{
public:virtual void func1() { cout << "BaseClass::func1()" << endl; }void func2() { cout << "BaseClass::func2()" << endl; }
};class DerivedClass: public BaseClass{void func1() { cout << "DerivedClass::func1()" << endl; }
};int main(){DerivedClass b;BaseClass*ptr = &b;ptr->func1();ptr->func2();
}
代码结果是:
DerivedClass:func1()
BaseClass:func2()
上面代码的目的是为了说明虚函数该怎么用,简单总结:
- 需要进行迟绑定的父类函数前加了关键字virtual;
- 子类重写了父类的虚函数;
- 使用父类指针指向子类对象
二.typedef void(*func)(void)的解释和使用
需要先知道:
- typedef 只对已有的类型进行别名定义,不产生新的类型;
- #define 只是在预处理过程对代码进行简单的替换。
这里定义了一个类型func,这种类型的变量是一个函数指针,指向一个返回值是void类型(前面的void的作用),并且没有参数(后面的(void)的作用)的函数.
在查询虚函数实现原理的过程中出现了上述语句:
int main()
{typedef void(*pFunc)(void);cout << "virtual function testing:" << endl;Base b;cout << "虚函数表地址:" << (int *)(&b) << endl;pFunc pfunc;pfunc = (pFunc)*((int *)(*((int *)(&b))));pfunc();pfunc = (pFunc)*((int *)(*((int *)(&b))) + 1);pfunc();pfunc = (pFunc)*((int *)(*((int *)(&b))) + 2);pfunc();
}
上述代码的目的是为了顺序执行虚函数列表中虚函数中的内容。
在这个出现在typedef的函数指针,先不解释*((int *)(*((int *)(&b))))的含义了(因为我也糊涂了),在这里我思考的是为什么要通过定义函数指针来验证虚函数列表中的排序和内容?没有其它的方式吗?
在这里我分析的是:因为想要访问虚函数表的内容,就只能拿到每个虚函数所对应的地址,这个地址是函数的地址,而并不是某个变量的地址,所以对于这种函数地址的情况,就只能通过使用函数指针来访问,也就不得不使用typedef void(*pFunc)(void);
但问题是我分析的*((int *)(*((int *)(&b))))并不是地址啊,哈哈哈