定义基类和派生类
//书中的Item_book类
#include <iostream> #include <string> using namespace std; class Item_base { public: Item_base(const string &book = "", double sales_price = 0.0):isbn(book), price(sales_price){}; string book() const { return isbn; } virtual double net_price(size_t n) const { return n * price; } virtual ~Item_base() { } private: string isbn; protected: double price; }
class Bulk_item : public Item_base { public: double net_price(size_t) const; private: size_t min_qty; // minimum purchase for discount to apply double discount; };
// if specified number of items are purchased, use discounted price double Bulk_item::net_price(size_t cnt) const { if (cnt >= min_qty) return cnt * (1 - discount) * price; else return cnt * price; }
// calculate and print price for given number of copies, applying any discounts void print_total(ostream &os, const Item_base &item, size_t n) { os << "ISBN: " << item.book() // calls Item_base::book << "\tnumber sold: " << n << "\ttotal price: " // virtual call: which version of net_price to call is resolved at run time << item.net_price(n) << endl; } Item_base base; Bulk_item derived; // print_total makes a virtual call to net_price print_total(cout, base, 10); // calls Item_base::net_price print_total(cout, derived, 10); // calls Bulk_item::net_price /*在第一个调用中,item 形参在运行时绑定到 Item_base 类型的对象,因此,print_total 内部调用 Item_base 中定义的 net_price 版本。在第二个调用中,item 形参绑定到 Bulk_item 类型的对象,从 print_total 调用的是 Bulk_item 类定义的 net_price 版本。
*/
//覆盖虚函数 Item_base *baseP = &derived; // calls version from the base class regardless of the dynamic type of baseP double d = baseP->Item_base::net_price(42);
1、访问控制
1)基类中的 private 成员
可访问:1)基类成员本身 2)友元
不可访问: 1)派生类 2)用户
2)基类的 protected成员
可访问:1)基类 2)友元 3)派生类本身
不可访问:1)用户
特殊性:派生类只能通过派生类对象访问基类的protected成员,不能访问基类对象的private成员。
例:
//Bulk_item 定义了一个成员函数,接受一个 Bulk_item 对象的引用和一个 Item_base 对象的引用, //该函数可以访问自己对象的 protected 成员以及 Bulk_item 形参的 protected 成员,但是, //它不能访问 Item_base 形参的 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 }tips :提供给派生类型的接口是 protected 成员和public 成员的组合。
2、动态绑定
1)要触发动态绑定,满足两个条件:
第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;
第二,必须通过基类类型的引用或指针进行函数调用。
2)如果调用非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数。
如果调用虚函数,则直到运行时才能确定调用哪个函数,运行的虚函数是引用所绑定的或指针所指向的对象所属类型定义的版本。
3、公用、私有和受保护的继承
1) 每个类控制它所定义的成员的访问。派生类可以进一步限制但不能放松对所继承的成员的访问。 |
-
如果是公用继承,基类成员保持自己的访问级别:基类的public 成员为派生类的public 成员,基类的protected 成员为派生类的protected 成员。
-
如果是受保护继承,基类的public 和protected 成员在派生类中为protected 成员。
-
如果是私有继承,基类的的所有成员在派生类中为private 成员。
class Base { public: void basemem(); // public member protected: int i; // protected member // ... }; struct Public_derived : public Base { int use_base() { return i; } // ok: derived classes can access i // ... }; struct Private_derived : private Base { int use_base() { return i; } // ok: derived classes can access i };
4、接口继承与实现继承
5、去除个别成员using
在 Derived 的 public 部分增加一个 using 声明。如下这样改变
Derived 的定义,可以使 size 成员能够被用户访问,并使 n 能够被从 Derived 派生的类访问:
class Derived : private Base { public: // maintain access levels for members related to the size of the object using Base::size; protected: using Base::n; // ... };6、默认访问级别
1)class 默认private继承
2)struct 默认public继承
7、友元关系不能被继承。
如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。
8、继承与static成员
如果基类定义 static 成员,则整个继承层次中只有一个这样的成员。