C++面试高频(五)之虚函数
1.虚函数可以是模板函数吗?⭐
虚函数不可以是模板函数,模板函数的实例化是在编译器编译整个程序期间发生的,而虚函数的调用是在运行时才确定的。
这确实是一个重要的区别,模板函数在编译期间会根据使用的类型生成相应的实例,而虚函数需要在运行时根据对象的实际类型进行调用。
对于含有虚函数的类,编译器需要为每个类生成一个虚函数表(vtable),以便在运行时进行动态绑定。虚函数表中存储着该类的虚函数的地址。而模板函数的实例化个数是在整个程序被编译完成之后才确定的,编译器无法为模板函数生成固定数量的虚函数表。
因此,C++ 编译器不允许将虚函数声明为模板函数。只有普通的成员函数可以模板化。
2.请你说说虚函数的工作机制⭐⭐⭐
- 在有虚函数的类中,当类实例化为对象时,会在对象的内存布局中添加一个指向虚函数表的指针。这个指针通常位于对象最开始的位置,也就是对象的 vptr(虚表指针)。
- 虚函数表是一个静态的表格,保存了类中所有虚函数的地址。这个虚函数表在内存中的位置通常是在代码段(.text)中,而不是在对象的实际内存中。
- 当子类继承了父类的时候,子类对象也会继承父类的虚函数表。当子类重写(override)父类中的虚函数时,会将虚函数表中对应的函数地址替换为子类的虚函数地址,从而实现了动态绑定和多态。
- 运行时,通过对象的 vptr 指针来访问虚函数表,并根据表中存储的函数地址调用相应的虚函数。这个调用过程是动态的,会根据实际对象的类型来选择正确的虚函数实现。
- 虚函数的实现确实会增加访问内存的开销,因为需要通过 vptr 指针来访问虚函数表,并进行间接的函数调用。这可能会带来一些性能上的损失。对于不需要多态性的函数,可以选择将其声明为非虚函数,以提高性能。
总结一下,虚函数的实现方式通常包括在对象中添加一个指向虚函数表的指针(vptr),虚函数表存储了虚函数的地址,子类继承并重写父类的虚函数时会替换相应的地址,通过 vptr 指针和虚函数表来实现动态绑定和多态。虚函数的实现会带来额外的内存访问开销。
3.虚函数表在什么时候创建?每个对象都有一份虚函数表吗?
- 虚函数表在编译阶段由编译器创建,并且对于每个类都只会创建一份虚函数表。每个类只有一个虚函数表。
- 虚函数表是类级别的静态成员,存储了类中所有虚函数的地址。
- 每个对象中包含一个虚函数表指针(vptr),它指向了所属类的虚函数表。每个对象通过自己的虚表指针来访问类的虚函数表。
- 对象之间共享类的虚函数表,它们的虚表指针指向同一个虚函数表。
- 每个类的派生类继承了基类的虚函数表,并可以在派生类中扩展和重写虚函数。派生类的虚函数表会包含基类的虚函数,并添加派生类自己的虚函数。派生类的虚函数表会替代基类的虚函数表。.
- 虚函数表只有一份,而有多少个对象,就对应多少个虚函数表指针。
4.请说说操作符重载?哪些操作符不能重载?⭐⭐
操作符重载是一种特殊的函数重载,可以使得某些运算符在对特定对象进行操作时具有自定义的行为。通过重载操作符,可以为自定义的类类型创建与内置类型相似的语法和行为。
当谈到操作符重载时,以下是一个简单的示例,展示了如何重载加法操作符(+)来实现两个自定义对象的相加:
#include <iostream> class MyNumber { private: int value; public: MyNumber(int val) : value(val) {} MyNumber operator+(const MyNumber& other) { return MyNumber(value + other.value); } int getValue() const { return value; } }; int main() { MyNumber num1(5); MyNumber num2(10); MyNumber sum = num1 + num2; std::cout << "The sum is: " << sum.getValue() << std::endl; return 0; }
然而,并不是所有的操作符都可以被重载。以下操作符不能被重载:
- 成员选择操作符(.):无法改变点操作符的行为。
- 展开操作符(::):它用于指定作用域,不能被重载。
- 条件运算符(?:):无法改变条件运算符的行为。
- sizeof:它是一个关键字,无法重载。
- typeid:它是一个运算符,无法重载。
5.什么是纯虚函数⭐
纯虚函数(Pure Virtual Function)是在基类中声明但没有提供实现的虚函数。它的声明形式为在函数原型后面加上= 0
。纯虚函数在基类中起到以下作用:
- 提供接口定义:纯虚函数在基类中定义了一种接口,规定了派生类必须实现的函数。基类通过纯虚函数定义了一组可供派生类实现的操作,从而实现了接口的定义。
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
BG双9,目前在某外企。打算把之前校招时做的笔记通过专栏发出来,本专栏适合于C/C++、嵌入式方向就业的同学,本篇面经总结数千篇面经的知识集合,实时更新全网最新的嵌入式/C++最新内容,囊括了C语言、C++、操作系统、计算机网络、嵌入式、算法与数据结构、数据库等一系列知识点,在我看来这些是求职者在面试中必须掌握的知识点。最后呢祝各位能找到自己合适的工作。