1 #include <iostream> 2 3 using namespace std; 4 5 class Quote{ 6 public: 7 string isbn() const; 8 virtual double net_price(size_t n) const; 9 10 }; 11 12 class Bulk_quote : public Quote{ 13 public: 14 double net_price(size_t) const override ; 15 16 }; 17 18 int main() { 19 20 }
1、 派生类必须在其内部对所有重新定义的虚函数进行声明。
派生类经常(但不总是)覆盖它继承的虚函数。如果派生类没有覆盖其基类中的某个虚函数,则该虚函数的行为类似于其它的普通成员,派生类会直接继承它在基类中的版本。
派生类可以在这样的函数之前加上virtual关键字,但是并不是非得这么做。C++11新标准允许派生类显式地注明它将使用哪个成员函数改写基类的虚函数,具体措施是在该函数的形参列表之后加一个overrride关键字。
2、 在C++语言中,当我们使用基类的引用或指针调用一个虚函数时将发生动态绑定。
1 Quote item; 2 Bulk_quote bulk; 3 Quote *p = &item; 4 p = &bulk; 5 Quote &r = bulk;
3、 virtual关键字只能出现在类内部的声明语句之前而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数。
4、在一个对象中,继承自基类的部分和派生类自定义的部分不一定是连续存储的。
5、 除非我们特别之处,否则派生类对象的基类部分会像数据成员一样执行默认初始化。如果我们想使用其他的基类构造函数,需要用类名()内传参为构造函数提供初始值。
1 #include <iostream> 2 3 using namespace std; 4 5 class Quote{ 6 public: 7 Quote() = default; 8 Quote(const std::string &book, double sales_price): bookNo(book),price(sales_price){}; 9 string isbn() const{ return bookNo;}; 10 virtual double net_price(size_t n) const{ 11 return n*price; 12 }; 13 14 virtual ~Quote() = default; 15 16 private: 17 string bookNo; 18 protected: 19 double price = 0.0; 20 }; 21 22 class Bulk_quote : public Quote{ 23 public: 24 Bulk_quote() = default; 25 Bulk_quote(const string& book, double p, size_t qty, double disc):Quote(book,p),min_qty(qty), 26 discount(disc){}; 27 double net_price(size_t) const override ; 28 29 private: 30 size_t min_qty = 0; 31 double discount = 0.0; 32 };
必须明确一点:每个类负责定义各自的接口。要想与类的对象交互必须使用该类的接口,即使这个对象是派生类的基类部分也是如此。
因此,派生类对象不能直接初始化基类的成员。尽管从语法上来说我们可以在派生类构造函数体内给它的public或protected基类成员赋值,但是最好不要这么做。和使用基类的其它场合一样,派生类应该遵循基类的接口,并通过调用基类的构造函数来初始化那些从基类中继承而来的成员。
6、 如果基类定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义。不论从基类中派生出多少个派生类,对每个静态成员来说都只存在唯一的实例。
可以使用作用域加方法名直接调用:Base::staticMem();
7、作基类的类必须已经定义,而不只是声明。
一个类是基类,同时它也可以是一个派生类。
8、 防止继承的发生:final关键字。
1 class NoDerived final {}; //NoDerived不能作为基类