• c++的多态,继承,抽象类,虚函数表,虚函数等题目+分析


    目录

    题目 

    代码题

    分析

    主观题


    题目 

    代码题

    1. class A
    2. {
    3. public:
    4. virtual void func(int val = 1) {
    5. std::cout << "A->" << val << std::endl;
    6. }
    7. virtual void test() {
    8. func();
    9. }
    10. };
    11. class B : public A
    12. {
    13. public:
    14. void func(int val = 0) {
    15. std::cout << "B->" << val << std::endl;
    16. }
    17. };
    18. int main(int argc, char* argv[])
    19. {
    20. B* p = new B;
    21. p->test();
    22. return 0;
    23. }

    A: A->0       B: B->1      C: A->1       D: B->0       E: 编译出错       F: 以上都不正确

    分析

    p调用了B中的test(),传入B的this指针

    • 但test()在B中没有,它是A中的函数,且没有被重写,所以需要去A中寻找
    • 而调用A中函数需要使用A类型的this指针,所以B类型的this指针被转换为A类型的
    • 而调用了test()后,里面又会调用func()
    • 别忘了,这里的this指针实际还是指向B的(只是指在了B中的A部分)
    • 所以,根据多态性,调用了B中的func,所以要打印B->
    • 注意这里的val
    • 多态实际上是使用了基类中函数的声明+子类中该函数的定义
    • 所以!!!val的值是A中的1(int val = 1)
    • 所以最后结果是B->1

     

    主观题

    1. 什么是多态?

    多态 -- 完成同一个动作,根据指针/引用实际指向的对象类型,来调用函数

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

    • 重载 -- 在同一作用域下,两个函数的名字相同,但参数列表/返回值不同
    • 重定义/隐藏 -- 在继承关系中,父类和子类都有一个同名函数,无论参数如何,都会构成隐藏,优先调用子类的函数
    • 重写/覆盖 -- 在继承关系中,父类和子类都有一个相同的虚函数(同名,同参数,同返回值),就说子类的该函数重写了父类的该函数 ; 当使用父类的指针/引用调用该函数时,会实际调用子类中的

    3. 多态的实现原理?

    虚函数+虚函数表+运行时多态性

    • 虚函数 -- 可以在派生类中被重写
    • 虚表 -- 存储类中虚函数的指针
    • 运行时多态性 -- 实现运行时可以根据实际对象调用对应函数

    4. inline函数可以是虚函数吗?

    可以

    • 但内联函数原本是不生成地址的,直接在调用处展开代码
    • 而虚函数需要将地址存入虚表
    • 所以一旦成为虚函数,就会失去内联的特性

    5. 静态成员可以是虚函数吗?

    不可以

    • 静态成员属于整个类,调用时直接使用类域即可
    • 虚函数调用需要传入this指针(需要this指针来找到该对象的虚表,在里面寻找虚函数),而静态成员没有this指针

    6. 构造函数可以是虚函数吗?

    不可以

    • 因为构造函数是用来初始化对象的,包括设置对象的虚表指针,而虚函数的调用依赖于虚表指针
    • 所以虚表和虚函数的机制依赖于已经正确初始化的对象 -- 构造函数->虚表指针->虚函数
    • 如果构造函数是虚函数,那么调用的时候需要依赖虚表找到虚函数,但虚表又是在构造函数之后才能创建好
    • 那么这个先后顺序就很迷惑了,所以不可以是虚函数

    7. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

    当然可以

    • 编译器会对析构函数的函数名做处理,从而达到虚函数的条件
    • 场景 -- 当需要使用基类类型的指针/引用指向派生类,而没有其他方法析构该派生类时(防止内存泄漏)

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

    普通函数更快

    • 因为虚函数需要在运行时,根据类型 -> 去对象中找虚表 ->在虚表中找虚函数
    • 而普通函数直接jmp到函数地址即可

    9. 虚函数表是在什么阶段生成的,存在哪的?

    • 编译阶段生成
    • 存在常量区

    10. C++菱形继承的问题?虚继承的原理?

    一个派生类对象中,会存储两份共同基类,造成数据冗余+二义性问题

    虚继承 :

    • 将基类声明成虚基类,该类在派生类中只存在一份
    • 会在包含它的派生类中,存放一份虚基表,使可以通过该表中存放的偏移量来访问基类

    11. 什么是抽象类?抽象类的作用?

    • 抽象类 -- 包含纯虚函数的类(纯虚函数 -- 在基类中的虚函数后加上=0)
    • 作用 -- 定义一个通用的接口,然后由具体的派生类来实现这个接口以提供不同的行为
  • 相关阅读:
    element 表单自定义效验规则
    推荐系统全流程落地实施方案
    JS中oninput和onchange事件的区别
    渗透测试-Kali Linux 正确清理垃圾的姿势
    windows下git提交修改文件名大小写提交无效问题
    Java 并发编程面试题——synchronized 与 volatile
    PaDiM 原理与代码解析
    【入门】上了大学,最好了解一点计算机视觉
    2.3IP详解及配置
    gulp来处理html、css、js资源啦
  • 原文地址:https://blog.csdn.net/m0_74206992/article/details/139798955