一、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;
}