2)如果派生类是受保护继承(protected inheritance)
  class Bulk_item:protected Item_base{...};
  基类中的public和protected成员 像派生类的中protected一样
  3)如果派生类是私有继承(private inheritance)
  class Bulk_item:private Item_base{...};
  基类中的public和protected成员 像派生类的中private一样,用户不能通过派生类对象访问基类中的任何成员。
  public派生类继承了基类的接口,可以在需要基类的地方使用public派生类。而private和protected派生类则不可以。
  可以用using 声明恢复基类成员在派生类中的访问级别。
  class和struct在定义继承类的,默认的继承类别也不同。
  class Base{...};
  class D1:Base{...} 等价于 class D1:private Base{...}
  struct D2:Base{...} 等价于 class D2:public Base{...}
  class 与 struct 用来定义类除了访问级别的不同外,其他没有任何不同。
  派生类的成员函数中不能直接访问基类类型对象的protected成员,但是可以通过派生类对象访问基类的protected成员。
  void Bulk_item::memfcn(const Bulk_item &d, const Item_base &b)
  {
  // price is protected
  double ret = price; //ok
  ret = d.price;//ok
  ret = b.price;//error
  }
  2.5 继承与静态成员
  如果基类定义了static成员,则在整个继承层次中只有一个这样的成员。
  2.6 防止继承的发生
  有时候我们会定义这样一种类,我们不希望其他类继承它,或者不想考虑它是否适合作为一个基类。C++11中允许在类名后加一个关键字final来防止继承。
  Class NoDerived final{/* */ }
  Class Bad : public NoDerived{/* */ } // error!
  3 派生类与基类之间的转换
  可以将基类的指针或引用绑定到派生类对象上有一层极为重要的含义:当使用基类的引用(或指针)时,实际上我们并不清楚该引用(或指针)所绑定对象的真实类型。该对象可能是基类的对象,也可能是派生类的对象。
  3.1 静态类型与动态类型
  表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型;动态类型则是变量或表达式表示的内存中的对象的类型,动态类型直到运行才可知。如果表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致。
  3.2 派生类转换为基类
  引用转换不同于对象转换
  1)将派生类对象传递给希望接受基类引用的函数,实际上传递进去的是原来的派生类对象,这个对象没有发生任何变化。
  2)而如果将派生类对象传递给希望接受基类对象的函数,实际上是将实参派生类对象中基类部分复制出来,创建了一个临时的基类对象。
  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;
};