C++面试题(4)| 你了解虚函数吗?

341 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

image.png

(欢迎大家关注我的微信公众号——控制工程研习,上面会分享很多我学习过程中总结的笔记。)

1. 构造函数可以是virtual吗?为什么不可以是virtual?

    构造函数是用来创建一个新的对象,而虚函数的运行是建立在对象的基础上,在构造函数执行时,对象尚未形成,所以不能将构造函数定义为虚函数,通常析构函数才会用virtual修饰(虚函数实际存放在对象的头部的虚函数表中的)

★2. 虚表指针是什么时候初始化的?

答案:

    虚表指针的初始化发生在构造函数过程中。

分析:

首先知道什么是虚表:

    编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一行。如果类中有N个虚函数,那么其虚函数表将有N4(x64下是N8)的大小。

    派生类的虚函数表存放重写的虚函数,当基类的指针指向派生类的对象时,调用虚函数时都会根据vptr(虚表指针)来选择虚函数,而基类的虚函数在派生类里已经被改写或者说已经不存在了,所以也就只能调用派生类的虚函数版本了.

什么是虚表指针呢?

    虚表指针在类对象中,每个同类对象中都有个一个vptr,指向内存中的vtable,所有同类对象,共享一个vtable,但是每个对象都自带一个vptr指向这个vtable,否则调用虚函数的时候会找不到正确的函数入口,虚表指针是对象的第一个数据成员。

    虚表(虚表存储在数据段)的地址存放在对象的起始位置,即对象的第一个数据成员就是它的虚表指针,同时需要注意到,虚表指针的初始化发生在构造函数过程中。

★3. 不考虑使用场景,除了构造函数,给所有函数都声明为virtual的,可以这样做吗?或者推荐这么做吗?有什么负面影响吗?

    静态成员函数(static)、友元函数不可以。

    除此之外,也不推荐这么做。因为大部分方法不需要被派生类重写,只有需要的才标virtual,还能起到告知作用。virtual关键字能起到沟通的作用,让人(包括你自己)在阅读代码时就知道这个函数存在继承关系,大概是什么用途。

    而且虚函数调用有重定向开销,把虚函数限定在需要的方法上面,控制了虚函数带来的开销。你不需要为你不使用的东西付出代价。此外,虚函数还会引入虚表和虚指针的开销。