某日二师兄参加XXX科技公司的C++工程师开发岗位第22面: (二师兄好苦逼,节假日还在面试。。。)
面试官:C++的继承了解吗?
二师兄:(不好意思,你面到我的强项了。。)了解一些。
面试官:什么是虚函数,为什么需要虚函数?
二师兄:虚函数允许在基类中定义一个函数,然后在派生类中进行重写(
override
)。二师兄:主要是为了实现面向对象中的三大特性之一多态。多态允许在子类中重写父类的虚函数,同样的函数在子类和父类实现不同的形态,简称为多态。
面试官:你知道
override
和finial
关键字的作用吗?二师兄:
override
关键字告诉编译器,这个函数一定会重写父类的虚函数,如果父类没有这个虚函数,则无法通过编译。此关键字可省略,但不建议省略。二师兄:
finial
关键字告诉编译器,这个函数到此为止,如果后续有类继承当前类,也不能再重写此函数。二师兄:这两个关键字都是C++11引入的,为了提升C++面向对象编码的安全性。
面试官:你知道多态是怎么实现的吗?
二师兄:(起开,我要开始装逼了!)C++主要使用了虚指针和虚表来实现多态。在拥有虚函数的对象中,包含一个虚指针(
virtual pointer
)(一般位于对象所在内存的起始位置),这个虚指针指向一个虚表(virtual table
),虚表中记录了虚函数的真实地址。
#include
struct Foo
{
size_t a = 42;
virtual void fun1() {std::cout
二师兄:当初始化虚表时,会把当前类override的函数地址写到虚表中(
Goo::fun1
、Goo::fun3
),对于基类中的虚函数但是派生类中没有override
,则会把基类的函数地址写到虚表中(Foo::fun2
),在调用函数的时候,会通过虚指针转到虚表,并根据虚函数的偏移得到真实函数地址,从而实现多态。面试官:不错。上图你画出了单一继承的内存布局,那多继承呢?
二师兄:多继承内存布局类似,只不过会多几个
virtual pointer
。
#include
struct Foo1
{
size_t a = 42;
virtual void fun1() {std::cout
面试官:你知道什么是菱形继承吗?菱形继承会引发什么问题?如何解决?
二师兄:菱形继承(
Diamond Inheritance
)是指在继承层次结构中,如果两个不同的子类B和C继承自同一个父类A,而又有一个类D同时继承B和C,这种继承关系被称为菱形继承。
二师兄:因为B和C各继承了一份A,当D继承B和C的时候就会有2份A;
#include
struct A
{
int val = 42;
virtual void fun(){std::cout
二师兄:解决的办法有两种,一种是在调用符之前加上父类限定符:
std::cout
二师兄:但这里并没有解决数据冗余的问题,因为D中有B和C,而B和C各有一个虚表和一个int类型的成员变量,所以
sizeof(D)
的大小是32(x86_64
架构,考虑到内存对齐)。二师兄:所幸在C++11引入了虚继承(
Virtual Inheritance
)机制,从源头上解决了这个问题:
#include
struct A
{
int val = 42;
virtual void fun(){std::cout
二师兄:此时在对象
d
中,只包含了一个val
和两个虚指针,成员变量的冗余问题得到解决。面试官:一般我们认为多态会影响性能,你举得为什么影响性能?
二师兄:大多数人认为,虚函数的调用会先通过虚指针跳到虚函数表,然后通过偏移确定函数真实地址,再跳转到地址执行,是间接调用导致了性能损失。
二师兄:但实际上无法内联才是虚函数性能低于正常函数的主要原因。由于多态是运行时特征,在编译时编译器并不知道指针指向的函数地址,所以无法被内联。同时跳转到特定地址执行函数可能引发的
L1 cache miss
(空间局部性不好),这也会影响性能。面试官:虚函数的调用一定是非内联的吗?
二师兄:不是。现代编译器很聪明,如果编译器能够在编译时推断出真实的函数,可能会直接内联这个虚函数。虚函数的调用是否内联取决于编译器的实现和上下文。
面试官:你觉得多态在安全性上有没有什么问题?
二师兄:的确是有的。当我们把类中的虚函数定义为
private
的时候,虽然我们不能通过类的对象去访问这个函数,但我们知道这个函数就在虚函数表中,可以通过特殊的方法(上文中已经给出示例)访问它:
#include
struct Foo
{
private:
virtual void fun() {std::cout
面试官:好的,今天的面试到这里就结束了,请回去等通知吧。
今天二师兄表现很不错,加个肉粽。感谢小伙伴的耐心阅读,祝各位小伙伴端午节牛逼(端午快乐->没文化,端午安康->跟风狗,好吧我祝各位端午牛逼~)。二师兄的C++面试之旅,明天不见不散~
关注我,带你21天“精通”C++!(狗头)
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net