C++ Primer 读书笔记 - 第十五章
1. OOP基于三个基本概念 - data abstraction,inheritance,dynamic binding. 其关键思想是多态性(polymorphism)。
2. 定义为virtual的函数是基类期待派生类重新定义的,基类希望派生类继承的函数不能定义为虚函数。
3. virtual关键字只能出现在类体内的声明中,不能出现在类体外的定义中。
4. 派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型对象的protected成员没有特殊访问权限。
void Bulk_item::memfcn(const Bulk_item &d, const Item_base &b) { //attempt to use protected member double ret = price; //ok: uses this->price ret = d.price; //ok: uses price from a Bulk_item object ret = b.price; //error: no access to price from an Item_base }
5. 子类继承了基类的所有成员,但对private成员没有访问权限。
6. 派生类一般会重定义所继承的虚函数,如果派生类没有重定义某个虚函数,则使用基类中定义的版本。
7. 派生类中虚函数的声明必须与基类中的定义方式完全匹配,但有一个例外:返回对基类型的引用(或指针)的虚函数。派生类中的虚函数可以返回基类函数所返回类型的派生类的引用(或指针)。
8. 一旦函数在基类中声明为虚函数,它就一直为虚函数,派生类无法改变该函数为虚函数这一事实。派生类重定义虚函数时,可以使用virtual关键字,但不是必须这样做。
9. 一个类在被当做基类使用之前,必须已经定义过。
10. C++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:
- 只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定。
- 必须通过基类类型的引用或指针进行函数调用。
11. static type at compile time, dynamic type at run time.
12. 使用scope operator 来覆盖virtual mechanism
Item_base *basep = &derived; double d = basep->Item_base::net_price(42);
13. Friendship does not inherit.
14. 如果基类定义了static成员,则整个继承层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个static成员只有一个实例。
15. 基类到派生类的转换:
Item_base base; Bulk_item *bulkp = &base; //error: cannot convert base to derived Bulk_item &bulkRef = base; //error: cannot convert base to derived Bulk_item bulk = base; //error: cannot convert base to derived Bulk_item bulk; Item_base *itemp = &bulk; //OK: dynamic type is Bulk_item Bulk_item *bulkp = itemp; //error: cannot convert base to derived
16. Constructors and the copy-control members are not inherited.
17. 派生类构造函数的写法:
class Disc_item : public Item_base { public: Disc_item(const string &book = "", double sales_price = 0.0,
size_t qty = 0, double disc_rate = 0.0) :
Item_base(book, sales_price),
quantity(qty), discount(disc_rate) { } protected: size_t quantity; double discount; };
18. 每个析构函数只负责清理自己的成员。
19. 像其他虚函数一样,析构函数的虚函数性质都将继承。因此,如果层次中根类的析构函数为虚函数,则派生类析构函数也将是虚函数,无论派生类显示定义析构函数还是使用合成析构函数,派生类析构函数都是虚函数。
20. 原始基类的析构函数应该定义为virtual,即使它什么事都不做。
21. 如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本。
22. 在编译期间,编译器会把所有类型当成静态类型,然后查找函数名。如果一个函数仅在派生类中定义了,用基类的指针是找不到它的,会产生编译错误。
23. The base class functions are considered only if the derived does not define the function at all.
24. 虚拟函数及作用域
#include <iostream> using namespace std; class Base { public: virtual void fcn() { cout << "Base::fcn()" << endl; }; }; class D1 : public Base { public: //hide fcn in the base; this fcn is not virtual void fcn(int p) { cout << "D1:fcn(int)" << endl; } //parameter list differs from fcn in Base void fcn(int a, int b) { cout << "D1::fcn(int, int)" << endl; } //D1 inherits definition of Base::fcn(), but it cannot be called from a D1 object }; class D2 : public D1 { public: void fcn(int p) { cout << "D2::fcn(int)" << endl; } //nonvirtual function hides D1::fcn(int) void fcn() { cout << "D2::fcn()" << endl; } //redefines virtual fcn from Base }; int main() { Base bobj; D1 d1obj; D2 d2obj; Base *bp1 = &bobj; Base *bp2 = &d1obj; Base *bp3 = &d2obj; bp1->fcn(); bp2->fcn(); bp3->fcn(); D1 *dd1 = &d1obj; ((Base*)dd1)->fcn(); dd1->fcn(); //error d1obj.fcn(); //error return 0; }
25. 在函数形参表后面写上=0以指定纯虚函数,创造抽象基类(abstract base class)会产生编译错误。
26. A class containing(or inheriting)one or more pure virtual functions is an abstract base class. We may not create objects of an abstract type except as parts of objects of classes derived from the abstract base.
27. 两个编程例子
可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明