面试 · C++虚继承与虚函数

Posted by Kang Cai on August 27, 2019

算法。文章首发于我的博客,转载请保留链接 ;)

通过 “/d1 reportAllClassLayout” 指令查看类内存布局**

虚继承

虚继承主要用于菱形形式的继承形式,是为了在多继承的时候避免引发歧义,避免重复拷贝。重要概念是 虚基类指针(vbptr)虚基类表(vftable)

1.普通继承

2.虚继承

其中基类 A 与普通继承一样,故省略;B 由于与 C 是一样的,故也省略。以类 C 为例,虚继承的子类中有个虚基类指针,虚基类指针指向对应的虚表,虚基类表中记录了到虚基类的偏移。甚至还可以做以下两个操作,

理解了类内存结构、虚基类指针、虚基类表的含义,就万变不离其宗了。

虚函数

虚函数继承是解决多态性的,当用基类指针指向派生类对象的时候,基类指针调用虚函数的时候会自动调用派生类的虚函数,这就是多态性,也叫动态编联。重要概念是 虚函数指针(vfptr)虚函数表(vftable)

1.虚函数

2.虚继承虚函数

单纯为的是看看类内存的结构

3.纯虚函数

纯虚函数相当于基类只提供接口而不定义具体实现,在函数声明后加=0,如: virtual void Eat() = 0。重要概念是 抽象类

在基类中不能对虚函数给出有意义的实现,凡是含有纯虚函数的类叫做抽象类。这种类不能声明对象,只是作为基类为派生类服务。除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。

一般而言纯虚函数的函数体是缺省的,但是也可以给出纯虚函数的函数体(此时纯虚函数变为虚函数),这一点经常被人们忽视,调用纯虚函数的方法为baseclass::virtual function。

Q&A

1.虚函数(virtual)能是static的吗?

不能,因为静态成员函数可以不通过对象来调用,即没有隐藏的this指针;而virtual函数一定要通过对象来调用,即有隐藏的this指针

2.能调用纯虚函数吗?

能,通过静态调用

3.抽象类的继承类不实现纯虚函数会怎样?

那么继承类本身也是抽象类,不能直接用来实例化对象。

4.C++类有继承时,析构函数必须为虚函数吗?

是的,如果不是虚函数,则使用时可能存在内在泄漏的问题。基类的指针去操作继承类的成员,释放指针P的过程是:只是释放了基类的资源,而没有调用继承类的析构函数。

5.C++中,构造函数能定义为虚函数吗

虚函数相应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。

参考资料

1.RTTI、虚函数和虚基类的实现方式、开销分析及使用指导