Cpp_继承和多态
内容
引入
类与类之间的关系:
组合/嵌套:一个类中声明了另一个类,是属于的关系。一个类是另一个类的一部分。
代理:一个类的接口是另一个类接口的子集
继承:fish–goldFish
隐藏
子类会隐藏父类的同名成员。----同名隐藏
访问被隐藏的成员需要加上(父类)作用域。
动多态
产生:使用指针或者引用调用虚函数,就会产生动多态调用
动多态调用的过程:
- 使用指针或者引用调用虚函数
- 在对象中找到vfptr
- 根据vfptr找到vftable
- 在vftable中找到要调用的函数
- 调用
vftable
编译时期如果发现类中有虚函数,就会对这个类生成vftable(虚函数表)。将当前
面试
- 父子类/组合类的构造顺序
- 先构造父类,再构造子类。
- 先构造内部类,再构造大类。
- 类的编译顺序:
- 编译类名
- 编译成员名=====编译嵌套类
- 编译成员方法体
- 什么是多态
- 面向对象方法学中,派生类继承基类后表现出来的形式叫多态。这个形式为在基类的行为基础上又派生出各自派生类的特性
- 动多态的产生条件
- 父类有虚函数
- 动多态的过程
- 子类继承父类时,拷贝父类虚函数表,覆盖虚函数表中的同名方法。
- 在调用子类方法时,如果发现其是虚函数,则由虚函数表指针找到虚函数表,查出函数指针,调用继承或重写的方法。
- vftable什么时候产生?在哪里存储?
- 在构造子类前,构造父类时产生。在内存的只读数据段中存储。
- 构造函数能不能写成虚函数
- 不能,因为调用虚函数需要去构造好的对象中找虚函数表指针。但是他还没构造出来。
- 静态函数能不能写成虚函数
- 静态函数属于类的函数,理论上可以被定义为虚函数并继承。
- 析构函数能不能写成虚函数
- 可以,并且在运用多态时,常用。
- 虚函数能不能被处理为内联
- 不能。内联是在编译期代码段展开,而动多态是在运行时。
- 什么情况下析构函数必须写成虚函数
- 父类指针指向子类对象
- 父类指针能不能指向子类对象?子类指针能不能指向父类对象?
- 前者可以,后者不可。
- 什么是RTTI?在什么时候产生?存储在哪里?
- 父类指针如何转化为子类指针?转化有什么条件?
- 什么是菱形继承?菱形继承有什么问题?如何解决?
- 纯虚函数有什么作用?
- 隐藏
- 覆盖
答案
-
- 静多态
- 编译时期的多态,又被称为早绑定
- 代表:函数重载、模板
- 动多态
- 运行时期的多态,又被称为晚绑定
- 代表:继承中的多态
- 静多态
-
- 编译类名
- 编译成员名=====编译嵌套类
- 编译成员方法体
-
- 指针或引用调用虚函数 + 对象必须完整
- 完整对象:构造函数执行完毕,虚构函数还没开始
-
- 使用指针或者引用调用虚函数
- 在对象中找到vfptr
- 找到vftable
- 在表中找到对应的函数
-
- 编译期产生
- 放在rodata区
-
- 不能,构造函数无法通过指针或者引用调用,写成虚函数没有意义。
- vfptr是在构造时才写入对象,而调用虚构造函数时没有对象构造出来。
-
不能,因为静态函数不依赖于对象。
-
- 不能。已内联的函数在编译期代码段展开,在release版本没有地址。
-
父类指针指向堆上的子类对象时,必须把父类的虚构函数写为虚函数。
-
- runtime type info,是一个指向类型信息的指针。
- 编译期产生,RTTI指针放在vftable里面,类型信息放在rodata段。
-
Derive* pd = dynamic_cast<Derive*>(p); dynamic_cast : 父类指针转为子类指针专用的类型强转 要求: 1.必须有RTTI 2.父类指针指向的对象中的RTTI确实是子类类型。 <!--code0-->