C++虚函数高频面试题及详细答案(实战版)_第1页
C++虚函数高频面试题及详细答案(实战版)_第2页
C++虚函数高频面试题及详细答案(实战版)_第3页
C++虚函数高频面试题及详细答案(实战版)_第4页
C++虚函数高频面试题及详细答案(实战版)_第5页
已阅读5页,还剩1页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++虚函数高频面试题及详细答案(实战版)一、基础概念题(入门必问)1.什么是虚函数?虚函数的作用是什么?答案:在C++中,被virtual关键字修饰的类成员函数就是虚函数。核心作用是实现多态(动态多态)。简单来说,就是用父类指针/引用指向子类对象时,调用的是子类重写的函数,而非父类的函数。普通成员函数是静态绑定(编译期确定调用哪个函数),虚函数是动态绑定(运行期根据对象真实类型确定调用函数)。2.虚函数和普通成员函数的核心区别?答案:绑定时机不同:普通函数编译期静态绑定;虚函数运行期动态绑定。调用规则不同:父类指针调用普通函数,永远执行父类方法;父类指针调用虚函数,执行子类重写的方法。内存开销不同:包含虚函数的类会生成虚函数表,对象会附带虚表指针,有少量内存开销;普通函数无额外开销。继承重写规则不同:普通函数子类同名函数会隐藏父类函数;虚函数子类同名同参函数会重写父类函数。3.什么是函数重写(覆盖)?重写的必要条件是什么?答案:重写是子类对父类虚函数的重新实现,是实现多态的前提。重写必备4个条件:存在父子继承关系父类函数必须是虚函数(带virtual)子类函数与父类函数函数名、参数列表、返回值完全一致(协变返回除外)访问权限不影响重写(private虚函数也可重写,只是外部无法调用)4.什么是函数隐藏?和重写的区别?答案:只要子类存在和父类同名的成员函数(无论参数是否相同),且父类函数不是虚函数,就会触发函数隐藏。此时父类的同名函数会在子类作用域中被屏蔽。核心区别:重写:针对虚函数,运行期动态绑定,实现多态隐藏:针对普通函数,编译期静态绑定,无多态二、底层原理题(面试重点)1.虚函数的底层实现原理是什么?答案:C++通过虚函数表(vtable)和虚表指针(vptr)实现虚函数和动态多态。1.虚函数表:每个包含虚函数的类,编译器会自动生成一张全局虚函数表,本质是存储虚函数地址的数组。子类会继承父类的虚表,若重写虚函数,会覆盖虚表中对应函数的地址;若新增虚函数,会在虚表末尾追加地址。2.虚表指针:每个该类的对象,都会在内存开头多出一个vptr指针,指向当前类的虚函数表。3.动态绑定流程:运行时,通过对象的vptr找到虚表,再根据函数下标取出对应函数地址,完成调用。2.虚函数表存在哪里?虚表指针存在哪里?答案:虚函数表:存储在全局静态数据区,一个类只存在一张虚表,所有对象共享,程序运行期间全程存在。虚表指针:存储在对象的内存空间中,每个对象独立拥有,创建对象时由构造函数初始化,销毁对象前随对象释放。3.构造函数和析构函数可以是虚函数吗?为什么?答案:1.构造函数不能是虚函数原因:虚函数的调用依赖对象的vptr,而构造函数执行时,对象尚未初始化完成,vptr还没有被赋值,无法通过虚表完成动态绑定。同时构造函数是创建对象,不存在“多态调用父类指针构造子类”的场景。2.析构函数建议声明为虚函数原因:当用父类指针指向子类对象,delete父类指针时,如果析构函数非虚,只会调用父类析构函数,子类资源无法释放,造成内存泄漏。声明为虚析构后,会动态绑定,先调用子类析构,再调用父类析构,完整释放资源。4.纯虚函数是什么?有什么作用?抽象类的特点?答案:纯虚函数是没有具体实现、仅声明接口的虚函数,语法:virtual函数原型=0;作用:定义统一的接口规范,强制子类必须实现该函数,否则子类也会成为抽象类,无法实例化。抽象类特点:包含纯虚函数的类即为抽象类无法创建实例对象可以拥有成员变量、普通成员函数、虚函数、构造/析构函数可以被继承,子类必须重写所有纯虚函数才能实例化三、代码实操题(手写判断)1.分析以下代码输出结果,并解释原因PlainText

#include<iostream>

usingnamespacestd;

classBase{

public:

virtualvoidshow(){

cout<<"Baseshow"<<endl;

}

};

classDerive:publicBase{

public:

voidshow(){

cout<<"Deriveshow"<<endl;

}

};

intmain(){

Base*p=newDerive();

p->show();

deletep;

return0;

}答案:输出结果:Deriveshow原因:show是虚函数,触发动态多态。父类指针p指向子类Derive对象,运行时通过虚表绑定子类重写的show函数,执行子类方法。2.去掉virtual关键字,重新分析输出结果答案:输出结果:Baseshow原因:无virtual修饰,函数为普通成员函数,编译期静态绑定。编译器根据指针类型(Base*)绑定父类函数,和指向的真实对象无关,触发函数隐藏。3.虚析构函数代码坑点分析PlainText

classBase{

public:

~Base(){cout<<"Base析构"<<endl;}

};

classDerive:publicBase{

public:

~Derive(){cout<<"Derive析构"<<endl;}

};

intmain(){

Base*p=newDerive();

deletep;

return0;

}答案:输出:仅打印Base析构问题:析构函数非虚,delete父类指针时,只调用父类析构,子类析构函数不执行,子类动态申请的内存、资源无法释放,造成内存泄漏。解决:给父类析构函数加virtual,变为虚析构,即可先析构子类、再析构父类。四、高频坑点&进阶面试题1.静态函数可以是虚函数吗?为什么?答案:不可以。核心原因两点:静态函数属于类,不属于对象,没有this指针;虚函数调用必须依赖对象的vptr和this指针,无调用基础。静态函数编译期确定,全局唯一,不支持动态绑定,和虚函数的多态特性完全冲突。2.内联函数可以是虚函数吗?答案:语法允许,实际无效。inline是编译期优化,虚函数是运行期动态绑定,二者冲突。如果虚函数被inline修饰,直接通过对象调用时,会触发内联优化;通过指针/引用调用时,会放弃内联,走虚表动态调用。工程中一般不将虚函数声明为内联。3.虚函数可以是private吗?有什么意义?答案:可以。private虚函数可以被子类重写,外部无法直接调用,但依然支持多态。常用于模板方法模式:父类提供公开接口,内部调用私有虚函数,由子类私有重写实现不同逻辑,封装性更强。4.多继承下的虚函数表有什么特点?会有什么问题?答案:1.多继承中,子类会继承多个父类的虚表,对象内存中会存在多个vptr,对应每个有虚函数的父类。2.子类重写父类虚函数时,会覆盖所有父类虚表中对应函数的地址,保证多态正常执行。3.常见问题:菱形继承导致虚表冗余、二义性,需要通过虚继承解决。5.虚函数存在的情况下,子类对象内存布局是怎样的?答案:单一继承无冗余布局:对象内存最开头:虚表指针vptr后续依次存放父类成员变量、子类新增成员变量注意:虚表不占用对象内存,仅vptr占用(32位

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论