热度 12
2016-4-29 20:11
1192 次阅读|
1 个评论
很多应用里面,会有相互联系而又细微不同的概念。 OOP(Object-oriented Programming)非常适合用在这样的场合。 15.1 Basic Concepts ---------------------------------------------------------------- OOP的核心思想是: data abstraction inheritance dynamic binding 派生类必须在自己的类里,定义基类的所有virtual函数。 使用基类做参数的场合,我们也可以使用派生类,这里用到了dynamic binding的技术。 dynamic binding是直到运行的时候,才知道调用哪个类的virtual函数,因此它又称为: run-time binding 15.2 Defining Base and Derived Classes ---------------------------------------------------------------- 基类必须定义一个virtual的析构函数。 virtual关键字不可用在构造函数上,不可出现在函数的定义上(只能用在类中的函数声明)。 派生类继承的virtual函数,会被隐式的设置为virtual。 protected表示,这个成员可以被派生类访问,但不能被外部访问。 derived-to-base conversion: 我们可以将一个基类的引用或指针,绑定到派生类(的基类part)上,比如: Bulk_quote bulk; Quote *p = bulk; Quote r = bulk; 派生类不能执行基类的成员初始化,因为: Each class controls how its members are initialized. 如果派生类想实现基类的成员初始化,它需要在自己的构造函数中调用基类的构造函数。 比如下面的代码: Bulk_quote(string isbn, double price) : Quote(isbn, price) {} 如果基类中有一个static成员,那么所有的派生类和基类都只会包含一个它。 声明派生类的时候,不能够加上后面的派生列表: class Bulk_quote : public Quote; //error class Bulk_quote; //OK final关键字,用来告诉编译器这个类不能被继承。 15.3 Virtual Functions ---------------------------------------------------------------- 当一个virtual函数被调用时,直到运行时编译器才知道应该调用哪一个版本。 这是通过引用或指针的dynamic type来判断的。 非virtual的函数在编译时就能指定。 当使用override关键字时,编译器会为我们检查此函数是不是override了基类中的函数。 virtual函数应该使用同样的基类default values参数,不管时基类还是派生类。 15.4 Abstract Base Classes ---------------------------------------------------------------- 如果定义一个纯虚函数? 在函数的末尾添加“= 0”: class Pure_quote : public Quote { public: Pure_quote() = default; virtual double net_price(size_t n) const = 0; }; 这也意味着我们不能够定义Pure_quote的对象,而是只能继承它。 具备纯虚函数的类,称为抽象基类。 15.5 Access Control and Interitance ---------------------------------------------------------------- protected成员可以被friend或者派生类访问。 friend或者派生类只能通过派生的对象来访问,不能通过基类来访问,比如: class Sneaky : public Base { friend void clobber(Sneaky); // can access Sneaky::prot_mem friend void clobber(Base); // can't access Base::prot_mem int j; // j is private by default }; 如果派生的friend可以访问Base,那么只需要随意定义一个这样的派生类即可。 如果D类继承自B类: * 只有当D类以public的方式继承B的时候,用户代码才可以使用derived-to-base转换。 * D的成员函数以及D的友元,能够使用这种转换,无论如何继承都可以。 * D派生类的成员函数以及它的友元,只有在public或者protected继承时,才能使用这种转换。 友元不可继承。 using可以用来改变访问的level。 15.6 Class Scope under Inheritance ---------------------------------------------------------------- 派生类的scope nested in基类中。 派生类的name会覆盖它的基类中的name(不推荐使用派生类的name覆盖掉基类的name)。 scope操作符可以用来指定name的lookup。 派生类的函数会覆盖它的基类中的同名函数,即使它们的参数列表不一样,因为它们的scope不同。 15.7 Constructors and Copy Control ---------------------------------------------------------------- 基类必须定义一个虚的析构函数。 当删除一个Quote指针时,可能实际删除的却是一个Bulk_quote指针,此时就要调用后者的析构函数。 当派生类进行copy操作时,它的基类会调用构造函数,除非我们显式的指定使用copy/move。 assig操作也是一样的。 如果基类没有定义assign操作或者copy/move,编译器会自动调用合适的copy或其他函数。 在构造函数或析构函数里面调用的virtual函数,一定是构造函数/析构函数本身的类所拥有的那个。 using关键字,可以用来使得派生类继承基类的构造函数, 比如: class Bulk_quote : public Disc_quote { public: using Disc_quote::Disc_quote; // inherit Disc_quote's constructors double net_price(std::size_t) const; }; 15.8 Containers and Inheritance ---------------------------------------------------------------- 一般来说,和继承相关的类,不要存放在容器中, 因此我们很难确认,是存基类还是存派生类;使用指针(smart指针)可以解决这个问题。