当前位置: 首页 > ai >正文

C++ 面向对象编程:多态相关面试简答题

母文章:✨C++ 多态:化身千万的代码魔法

在母文章的讲解里,我们通过代码和具体的样例,针对面向对象三大特性之一的多态进行了详细的讲解,接下来在这篇子文章中,我们会进行多态相关面试题的简答题的汇总。

  • 什么是多态?

多态是指不同类型的对象能够有一个统一的调用接口,或者一个统一的关键字能够构成多种不同的行为,能够通过同名函数调用实现不同效果的行为就叫做多态。

  • 什么是隐藏(重定义)、重写(覆盖)和重载?

  • 隐藏(重定义)是指基类和派生类之间具有同名的成员函数/成员变量,就会构成隐藏。如果是派生类实例化的对象区调用构成隐藏的成员,则只会调用派生类自己作用域的成员,如果要调用基类对应的成员,则必须声明类域
  • 重写(覆盖)需要在满足成员函数隐藏的条件下,要在基类的函数前加上virtual修饰使其变为虚函数,并且派生类在重写(覆盖)基类的虚函数时还要满足参数的相同,一般返回类型也必须相同(返回类型如果不同,那么则构成协变关系)
  • 重载是指在同一作用域函数名相同的情况,参数列表必须不同,对返回值类型不作要求
  • 多态的实现原理是什么?

多态的实现原理是借用虚函数表,在运行时根据不同的对象来判断具体调用哪一个虚函数

调用虚函数时,主要是经历一下三个步骤:

  1. 通过对象的vptr(虚函数表指针)找到其类的vtable(虚函数表)。

  2. 在vtable中找到对应函数的地址。

  3. 调用该函数,并隐式地传入一个this指针,该指针指向调用它的那个具体对象。
    这个过程被称为“动态绑定”或“晚期绑定”。

  • 静态成员函数能不能被设计为虚函数?

静态成员函数是不能被设计为虚函数的。

静态成员实际上算是存在于类作用域的普通全局函数,并不是被成员对象指针或者引用进行调用的,并且是在编译时直接就确定好函数地址的。

所以在调用静态成员函数时,函数内部是没有this指针的(违背了多态的构成条件:必须是基类的指针或者引用区调用虚函数),就无法构成虚函数的调用。所以不能被设计为虚函数。

class Device {
public:// 虚函数:统一的“开启”接口virtual void turnOn() {std::cout << "设备已开启" << std::endl;}// 虚析构函数(很重要)virtual ~Device() {} //如果static前加了virtual会报错:error C2216: “virtual”不能和“static”一起使用static void func(){cout << "static void func()" << endl;}
};
  • inline内联函数能不能被设计为虚函数?

内联函数是可以被设计为虚函数的。

  • 在构成多态调用的情况下,编译器会自动忽略内联属性,不会直接在代码段展开函数。
  • 但如果是一般对象直接调用内联虚函数,不构成多态,编译器会根据内联属性展开代码段。
  • 构造函数可以被设计为虚函数吗?

构造函数不能被设计为虚函数的、,因为对象的虚函数表地址的链接是在构造对象时才被确定的,无法被设计为虚函数。

  • 析构函数可以被设计为虚函数吗?

析构函数是可以被并且被建议设计为虚函数的,这样的有助于进行析构对象时的多态行为,因为编译器会把析构函数的名词统一变为destructor构成多态行为,防止在析构派生类对象时出现内存泄漏的问题。

  • 对象访问普通函数更快还是访问虚函数更快?

  • 如果不构成多态行为,对象访问普通函数和虚函数是一样快的
  • 如果构成多态行为,访问虚函数的效率会比普通函数慢一些,因为调用虚函数,会通过虚函数表地址找到虚函数表,然后再访问对应的虚函数地址。
  • 虚函数表是在什么阶段编译生成的?存放在内存的哪片区域?

虚函数表在编译阶段生成,并最终存放在进程内存常量区的代码段中。

  • 菱形继承容易造成的问题?虚继承的原理是什么?

菱形继承容易造成数据冗余二义性问题。

虚继承的原理就是在继承对象时,编译器会把虚继承的基类子对象存放在对象的末尾,并且基类子对象在继承的过程中只保留一份,这样无论派生类继承多少次,都只会存在一份基类子对象。

  • 什么是抽象类?抽象类的作用是什么?

含有纯虚函数(只有声明没有实现的虚函数)的类就叫做抽象类。

抽象类的作用是变相强制要求派生类对纯虚函数进行重写,因为抽象类无法实例化出对象

就像这一概念和车品牌的关系(is-a继承关系),车这一概念无法单独存在现实存在的车子必须是有品牌的。

http://www.xdnf.cn/news/20268.html

相关文章:

  • 444444
  • LeetCode - 1089. 复写零
  • MQTT 与 Java 框架集成:Spring Boot 实战(三)
  • RAG提示词分解
  • CentOS系统管理:useradd命令的全面解析
  • Vllm-0.10.1:通过vllm bench serve测试TTFT、TPOT、ITL、E2EL四个指标
  • 多线程任务执行窗体框架jjychengTaskWinForm
  • 浅析Linux内核scatter-gather list实现
  • SQL 实战指南:电商订单数据分析(订单 / 用户 / 商品表关联 + 统计需求)
  • WordPress过滤文章插入链接rel属性noopener noreferrer值
  • 开源与定制化对比:哪种在线教育系统源码更适合教育培训APP开发?
  • 企业微信智能表格高效使用指南
  • Kafka Exactly-Once 语义深度解析与性能优化实践指南
  • 串口发送数据
  • 如何离线安装 VirtualMachinePlatform
  • 基于STM32单片机的家庭医护血氧体温血压吃药监测APP系统
  • 万字长文详解 MyCat 分表分库:从 0 到 1 构建高可用订单系统
  • 能发弹幕的简单视频网站
  • 计算机网络:调制解调器
  • Docker-volume数据卷
  • 为什么固态硬盘断电后数据还能保存不丢失?
  • 【LeetCode热题100道笔记】二叉树展开为链表
  • 激光频率梳 3D 轮廓测量 - 油路板的凹槽深度和平面度测量
  • Spring核心-Bean周期
  • ElmentUI之DateTimePicker 日期时间选择器
  • 避免使用非const全局变量:C++中的最佳实践 (C++ Core Guidelines)
  • SQLSERVER数据备份
  • Java8 Comparator接口 和 List Steam 排序使用案例
  • 人工智能在医学图像中的应用:从机器学习到深度学习
  • 技术方案详解:如何安全移动已安装软件?