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

目录

题目

代码题

分析

主观题


题目

代码题

cpp 复制代码
class A
{
public:
    virtual void func(int val = 1) {
        std::cout << "A->" << val << std::endl;
    }
    virtual void test() { 
        func(); 
    }
};

class B : public A
{
public:
    void func(int val = 0) { 
        std::cout << "B->" << val << std::endl;
    }
};

int main(int argc, char* argv[])
{
    B* p = new B;
    p->test();
    return 0;
}

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. 什么是重载、重写(覆盖)、重定义(隐藏)?

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

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

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

可以

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

不可以

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

不可以

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

当然可以

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

普通函数更快

  • 因为虚函数需要在运行时,根据类型 -> 去对象中找虚表 ->在虚表中找虚函数
  • 而普通函数直接jmp到函数地址即可
  1. 虚函数表是在什么阶段生成的,存在哪的?
  • 编译阶段生成
  • 存在常量区
  1. C++菱形继承的问题?虚继承的原理?

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

虚继承 :

  • 将基类声明成虚基类,该类在派生类中只存在一份
  • 会在包含它的派生类中,存放一份虚基表,使可以通过该表中存放的偏移量来访问基类
  1. 什么是抽象类?抽象类的作用?
  • 抽象类 -- 包含纯虚函数的类(纯虚函数 -- 在基类中的虚函数后加上=0)
  • 作用 -- 定义一个通用的接口,然后由具体的派生类来实现这个接口以提供不同的行为
相关推荐
Dontla17 分钟前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust
Ttang2323 分钟前
Leetcode:118. 杨辉三角——Java数学法求解
算法·leetcode
喜欢打篮球的普通人23 分钟前
rust模式和匹配
java·算法·rust
java小吕布37 分钟前
Java中的排序算法:探索与比较
java·后端·算法·排序算法
tumu_C1 小时前
C++模板特化实战:在使用开源库boost::geometry::index::rtree时,用特化来让其支持自己的数据类型
c++·开源
杜若南星1 小时前
保研考研机试攻略(满分篇):第二章——满分之路上(1)
数据结构·c++·经验分享·笔记·考研·算法·贪心算法
路遇晚风1 小时前
力扣=Mysql-3322- 英超积分榜排名 III(中等)
mysql·算法·leetcode·职场和发展
Neophyte06081 小时前
C++算法练习-day40——617.合并二叉树
开发语言·c++·算法
木向1 小时前
leetcode104:二叉树的最大深度
算法·leetcode