当我们使用容器存放继承体系中的对象时,通常必须采用间接存储的方式。因为不允许在容器中保存不同类型的元素,所以不能把具有继承关系的多种类型的对象之间存放在容器中。
在容器中放置(智能)指针而非对象
vector<shared_ptr<Quote>> basket;
basket.push_back( make_shared<Quote>("0-201-82470-1", 50));
basket.push_back( make_shared<Bulk_quote>("0-201-82470-1", 50, 10, 0.25));
//调用Quote定义的版本;打印562.5,即在15*50*(1-0.25)
cout << basket.back()->net_price(15) << endl;
编写Basket类
对于C++面向对象的变成来说,一个悖论是我们无法直接使用对象进行面向对象变成。相反,我们必须使用指针和引用。因为指针会增加程序的复杂性,所以我们经常定义一些辅助的类来处理这种复杂的情况:
class Basket {
public:
//Basket使用合成的默认构造函数和拷贝控制成员
void add_item( const std::shared_ptr<Quote> &sale)
{ items.insert(sale);}
//打印每本书的总价和购物篮中所有书的总价
double total_receipt( std::ostream&) const;
private:
//该函数用于比较shared_ptr,multiset成员会用到它
static bool compare( const std::shared_ptr<Quote> &lhs,
const std::shared_ptr<Quote> &rhs)
{ return lhs.isbn() < rhs->isbn();}
//multiset保存多个报价,按照compare成员排序
std::multiset<std::shared_ptr<Quote>, decltype(compare)*> items(compare);
};
double Basket::total_receipt( ostream &os) const
{
double sum =0.0;
for( auto iter = items.cbegin(); iter != items.cend();
iter = items.upper_bound(*iter))
{
sum += print_total(os, **iter, items.count(*iter));
}
os << "Total Sale:" << sum << endl;
return sum;
}
隐藏指针
Basket的用户必须处理动态内存,因为add_item需要接受一个shared_ptr参数。
Basket bsk;
bsk.add_item(make_shared<Quote>("123", 45));
bsk.add_item(make_shared<Bulk_quote>("345", 45, 3, 0.15));
下一步重新定义add_item,使其接受一个Quote对象而非shared_ptr。新版本的add_item将负责处理内存分配:
void add_item( const Quote& sale);
void add_item( Quote&& sale);
为了防止Bulk_quote对象在该函数使用时被迫切掉一部分
模拟虚拷贝
class Quote{
public:
//该虚函数返回当前对象的一份动态分配的拷贝
virtual Quote* clone() const & { return new Quote(*this);}
virtual Quote* clone() && { return new Quote(std::move(*this)); }
};
class Bulk_quote : public Quote{
public:
virtual Bulk_quote* clone() const & { return new Bulk_quot(*this);}
virtual Bulk_quot* clone() &&
{ return new Bulk_quot(std::move(*this));
};
class Basket {
public:
void add_item( const Quote &sale)
{ items.insert(std::shared_ptr<Quote>(sale.clone()); }
void add_item( Quote &&sale)
{ items.insert(std::shared_ptr<Quote>(std::move(sale).clone()); }
};