Cpp_继承和多态

内容

引入

类与类之间的关系:

组合/嵌套:一个类中声明了另一个类,是属于的关系。一个类是另一个类的一部分。

代理:一个类的接口是另一个类接口的子集

继承:fish–goldFish

隐藏

子类会隐藏父类的同名成员。----同名隐藏

访问被隐藏的成员需要加上(父类)作用域。

动多态

产生:使用指针或者引用调用虚函数,就会产生动多态调用

动多态调用的过程:

  1. 使用指针或者引用调用虚函数
  2. 在对象中找到vfptr
  3. 根据vfptr找到vftable
  4. 在vftable中找到要调用的函数
  5. 调用

vftable

编译时期如果发现类中有虚函数,就会对这个类生成vftable(虚函数表)。将当前

面试

  1. 父子类/组合类的构造顺序
    1. 先构造父类,再构造子类。
    2. 先构造内部类,再构造大类。
  2. 类的编译顺序:
    1. 编译类名
    2. 编译成员名=====编译嵌套类
    3. 编译成员方法体
  3. 什么是多态
    1. 面向对象方法学中,派生类继承基类后表现出来的形式叫多态。这个形式为在基类的行为基础上又派生出各自派生类的特性
  4. 动多态的产生条件
    1. 父类有虚函数
  5. 动多态的过程
    1. 子类继承父类时,拷贝父类虚函数表,覆盖虚函数表中的同名方法。
    2. 在调用子类方法时,如果发现其是虚函数,则由虚函数表指针找到虚函数表,查出函数指针,调用继承或重写的方法。
  6. vftable什么时候产生?在哪里存储?
    1. 在构造子类前,构造父类时产生。在内存的只读数据段中存储。
  7. 构造函数能不能写成虚函数
    1. 不能,因为调用虚函数需要去构造好的对象中找虚函数表指针。但是他还没构造出来。
  8. 静态函数能不能写成虚函数
    1. 静态函数属于类的函数,理论上可以被定义为虚函数并继承。
  9. 析构函数能不能写成虚函数
    1. 可以,并且在运用多态时,常用。
  10. 虚函数能不能被处理为内联
    1. 不能。内联是在编译期代码段展开,而动多态是在运行时。
  11. 什么情况下析构函数必须写成虚函数
    1. 父类指针指向子类对象
  12. 父类指针能不能指向子类对象?子类指针能不能指向父类对象?
    1. 前者可以,后者不可。
  13. 什么是RTTI?在什么时候产生?存储在哪里?
  14. 父类指针如何转化为子类指针?转化有什么条件?
  15. 什么是菱形继承?菱形继承有什么问题?如何解决?
  16. 纯虚函数有什么作用?
  17. 隐藏
  18. 覆盖

答案

    1. 静多态
      1. 编译时期的多态,又被称为早绑定
      2. 代表:函数重载、模板
    2. 动多态
      1. 运行时期的多态,又被称为晚绑定
      2. 代表:继承中的多态
    1. 编译类名
    2. 编译成员名=====编译嵌套类
    3. 编译成员方法体
    1. 指针或引用调用虚函数 + 对象必须完整
    2. 完整对象:构造函数执行完毕,虚构函数还没开始
    1. 使用指针或者引用调用虚函数
    2. 在对象中找到vfptr
    3. 找到vftable
    4. 在表中找到对应的函数
    1. 编译期产生
    2. 放在rodata区
    1. 不能,构造函数无法通过指针或者引用调用,写成虚函数没有意义。
    2. vfptr是在构造时才写入对象,而调用虚构造函数时没有对象构造出来。
  1. 不能,因为静态函数不依赖于对象。

    1. 不能。已内联的函数在编译期代码段展开,在release版本没有地址。
  2. 父类指针指向堆上的子类对象时,必须把父类的虚构函数写为虚函数。

    1. runtime type info,是一个指向类型信息的指针。
    2. 编译期产生,RTTI指针放在vftable里面,类型信息放在rodata段。
  3. Derive* pd = dynamic_cast<Derive*>(p);
    dynamic_cast : 父类指针转为子类指针专用的类型强转
    要求:
        1.必须有RTTI
        2.父类指针指向的对象中的RTTI确实是子类类型。
    <!--code0-->