3)派生类对象转换为基类对象实际上像是做了“裁切”操作。
3.3 基类转换为派生类
没有从基类类型到派生类型的(自动)转换,因为派生类中很可能包含了基类中没有成员。甚至当基类指针或引用实际绑定到派生类对象时,从基类到派生类的转换也存在限制。
Bulk_item bulk; Item_base *itemP = &bulk; // ok Bulk_item *bulkP = itemP; // error
4 虚函数
1)引用或指针的静态类型与动态类型不同这一事实正是C++语言支持多态性的根本所在。
2)基类中的虚函数在派生类中隐含地也是一个虚函数。当派生类覆盖了某个虚函数时,该函数在基类中的形参必须与派生类中的形参严格匹配。
3)可以是函数的形参表后加override说明函数是派生类中的虚函数,而用final用于说明不希望在继承类中覆盖该函数。
4)如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行时该调用将被解析为对派生类版本自身的调用,从而导致无限递归。
double undiscounted = baseP->Quote::net_price(42);
5)如果我们通过基类的引用或指针调用函数,则使用基类中定义的默认实参,即使实际运行的是派生类中的函数版本也是如此。
5 抽象基类
1)在虚函数的形参表后加=0会让虚函数变为纯虚函数,纯虚函数本身不需要定义,它只是为派生类提供一个接口用于表示抽象普适的意义。值得注意的是,我们也可以为纯虚函数提供定义,不过函数体必须定义在类的外部。
2)含有(或者未经覆盖直接继承)纯虚函数的类是抽象基类。抽象基类负责定义接口,而后续的其他类可以覆盖该接口。我们不能定义一个抽象基类的对象。
3)派生类构造函数只初始化它的直接基类。
class Disc_quote :public Quote { public: Disc_quote() = default; Disc_quote(const string& book, double price, size_t qty, double disc) : Quote(book, price), quantity(qty), discount(disc){} double net_price(size_t)const = 0; protected: size_t quantity = 0; double discount = 0.0; }; class Bulk_quote :public Disc_quote { public: Bulk_quote() = default; Bulk_quote(const string &book, double price, size_t qty, double disc) : Disc_quote(book, price, qty, disc){} double net_price(size_t)const override; };