一、static类成员
1、static类成员是与类相关联的,类定义时就存在,它独立于类的任何对象而存在。因此可以通过类、类的对象、类的对象指针、类的对象的引用来访问,同时也说明了他没有this指针。
2、static相当于一个全局变量。但是它可以是私有的(可以实施封装)。
3、static成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。
4、static 成员函数不能被声明为 const(注意,是成员函数,不是成员变量,成员变量可以为static const类型)。毕竟,将成员函数声明为const 就是承诺不会修改该函数所属的对象。
5、static 成员函数也不能被声明为虚函数。
二、纯虚函数
1、在函数形参表后面写上 = 0 以指定纯虚函数:
class Disc_item : public Item_base { public: double net_price(std::size_t) const = 0; };
2、定义了纯虚函数后,包含该纯虚函数的类将无法实例化,只能被其他类继承(抽象基类)。
3、派生类如果继承了抽象基类,而在该派生类中没有对此纯虚函数进行定义 则该派生类扔为抽象类 不能用它实体定义对象
三、容器与继承
1、句柄的引入
如果定义 multiset 保存基类类型的对象: multiset<Item_base> basket; Item_base base; Bulk_item bulk; basket.insert(base); // ok: add copy of base to basket basket.insert(bulk); // ok: but bulk sliced down to its base part
一旦对象放入了 multiset,它就不再是派生类对象了。容器中加入派生类型的对象时,只将对象的基类部分保存在容器中。记住,将派生类对象复制到基类对象时,派生类对象将被切掉
2、定义句柄类
句柄类将有两个数据成员,都是指针:一个指针将指向
基类 对象,而另一个将指向使用计数。句柄类 指针可以指向
基类对象也可以指向基类的 派生类型的对象。通过指向使用计数,多个 句柄类 对象可以共享同一计数器。(类似于智能指针)
3、句柄类与容器
#include <iostream> #include <string> #include <set> using namespace std; class Item_base { public: Item_base(const string &book = "", double sales_price = 0.0):isbn(book), price(sales_price){};//构造函数 Item_base(const Item_base &other) { isbn = other.isbn; price = other.price; } virtual Item_base* clone() const//为了使句柄类能够复制未知类型而定义 { return new Item_base(*this); }; 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 Disc_item : public Item_base //Disc_item为虚基类 { 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){}; ~Disc_item(); protected: size_t quantity; // purchase size for discount to apply double discount; // fractional discount to apply //纯虚函数,该类无法实例化,只能被其他类继承 double net_price(size_t) const = 0;//discount }; class Bulk_item : public Disc_item { //1、派生类的构造函数: //派生类构造函数只能初始化自己的直接基类,在 Bulk_item 类的构造函数初始化列表中指定 Item_base 是一个错误。 public: Bulk_item(const string& book = "", double sales_price = 0.0, size_t qty = 0, double disc_rate = 0.0): Disc_item(book, sales_price, qty, disc_rate) { }; ~Bulk_item(); Bulk_item* clone() const//为了使句柄类能够复制未知类型而定义 { return new Bulk_item(*this); } //2、关于派生类的复制构造函数: //只包含类类型或内置类型数据成员、不含指针的类一般可以使用合成操作,复制、赋值或撤销这样的成员不需要特殊控制。 //具有指针成员的类一般需要定义自己的复制控制来管理这些成员 protected: double net_price(size_t n) const { return n*price; }; private: }; class Sales_item //句柄类 use counted handle class for the Item_base hierarchy { public: // default constructor: unbound handle Sales_item(): p(0), use(new size_t(1)) { }; // 句柄的复制构造函数,attaches a handle to a copy of the Item_base object //为了句柄类,需要从基类开始,在继承层次的每个类型中增加 clone,基类必须将该函数定义为虚函数 Sales_item(const Item_base &item):p(item.clone()), use(new size_t(1)) { }; // copy control members to manage the use count and pointers Sales_item(const Sales_item &i):p(i.p), use(i.use) { ++*use; } ~Sales_item() { decr_use(); } Sales_item& operator=(const Sales_item &rhs) // use-counted assignment operator; use is a pointer to a shared use count { ++*rhs.use; decr_use(); p = rhs.p; use = rhs.use; return *this; }; // member access operators const Item_base* operator->() const { if (p) return p; else throw std::logic_error("unbound Sales_item"); } const Item_base& operator*() const { if (p) return *p; else throw std::logic_error("unbound Sales_item"); } // 比较函数,compare defines item ordering for the multiset in Basket inline bool compare(const Sales_item &lhs, const Sales_item &rhs) { return lhs->book() < rhs->book(); } private: Item_base *p; // pointer to shared item size_t *use; // pointer to shared use count // called by both destructor and assignment operator to free pointers void decr_use() { if (--*use == 0) { delete p; delete use; } } }; class Basket//跟踪销售并计算购买价格 { typedef bool (*Comp)(const Sales_item&, const Sales_item&);//这个语句将 Comp 定义为函数类型指针的同义词,该函数类型与我们希望用来比较 Sales_item 对象的比较函数相匹配。 public: // make it easier to type the type of our set typedef multiset<Sales_item, Comp> set_type; // typedefs modeled after corresponding container types typedef set_type::size_type size_type; typedef set_type::const_iterator const_iter; Basket(): items(compare) { } // initialze the comparator void add_item(const Sales_item &item) { items.insert(item); } size_type size(const Sales_item &i) const { return items.count(i); } double total() const; // 返回购物篮中所有物品的价格 { double sum = 0.0; // holds the running total /* find each set of items with the same isbn and calculate * the net price for that quantity of items * iter refers to first copy of each book in the set * upper_bound refers to next element with a different isbn */ for (const_iter iter = items.begin(); iter != items.end(); iter = items.upper_bound(*iter)) { // we know there's at least one element with this key in the Basket // virtual call to net_price applies appropriate discounts, if any sum += (*iter)->net_price(items.count(*iter)); } return sum; } private: multiset<Sales_item, Comp> items; }; int main() { Item_base base("0-201-82470-1", 20); // Disc_item无法实例化 // Disc_item Disc("0-201-82470-1", 20, 19, 19); Bulk_item bulk("0-201-82470-1", 20, 19, 19); multiset <Sales_item> basket;//购物车 basket.insert(base); basket.insert(bulk); cout<<base.book(); return 0; }