Chapter 15 OOP 面向对象程序设计
这一节主要讲基类和派生类之间的关系和注意细节.
派生类对于和基类的同名函数, 采取覆盖的方式静态绑定. 对于virtual
的虚函数, 采取动态绑定的方式. 何为动态绑定? 比如Base *p = &derive
, 对于p的常规成员函数, 执行基类的方法, 对于虚函数, 执行派生类的方法. 因为p指向的可能是基类也可能是派生类, 因此只能在运行时才确定, 所以为动态绑定.
在函数名的后面显式地说明override
, 告诉编译器这个函数是为了覆盖基类的虚函数, 而不是手误写了一个新的函数.
在类名后面说明final
, 说明这个类是不可以继承的.
virtual在派生类定义的时候也可以写上virtual, 那么派生派生类必须再次定义.
virtual函数在实现的时候和基类的声明参数完全一致, 否则就是一个新函数.(除了返回值是Base&
的情况)
虚函数可以有默认实参, 但是在派生类调用实现的新版本的时候仍然使用原来的默认实参.
指针的转换
Base *p1 = &derived;
Derived *p2 = p1;// 不可以直接转换
如果我们确定这种转换是安全的, 则可以使用static_cast
进行转换, 编译器忽略可能的错误. 或者使用dynamic_cast
, 编译器在运行时进行安全检查.
函数 = 0, 是一个纯虚函数, 没有实体(抽象基类)
基类访问说明符: 决定了派生类的成员和基类的用户是否有访问权限
派生访问说明符: 决定了派生类的用户是否有访问权限
友元不被继承.
using Base::func
可以无视派生访问说明符, 自定义派生类型
即使参数不同, 派生类的成员函数也会隐藏原来的. 因此对于基类的重载函数要么全都直接继承, 要么全都重载. 解决方法是: using Base::func
, 先把所有的重载函数继承过来, 然后再部分修改.
虚析构函数: 将析构函数声明称virtual, 防止Base *p = &derived;
销毁时调用基类的析构. 派生类的析构函数只需要析构自己的新成员.
对象在构造和析构的时候, 他的类是发生变化的.(从基类->派生类), 和成员的构造顺序一致.
构造函数也可以继承, 使用using Base::Base
, 作用是使用基类的构造函数, 同时派生类的新成员奖杯默认初始化.
如果想把基类的对象和派生类的对象存在一起, 那么应该使用智能指针, 类型是基类. 通过虚函数进行内容区分.