在C++中的容器或是数组中保存具有集成关系的类的对象,会导致派生类对象被强制转换为基类的对象。这样就会导致派生类对象被切割。所以不能直接在容器中存储这样的对象。其中一种解决的办法是存储指向对象的指针。这样又会带来一种问题,我们拷贝容器内容或是堆栈上的对象被释放的时候会出现悬空的指针,重复释放一个地址,或者是堆上保留了多份的对象拷贝。这些情况带来的影响都是不断扩大的,以至于最终超出控制。所以常采取的方案是采用智能指针的方法(句柄的概念)。我们的句柄类中保存了对象的指针和引用的计数。这样一来,我们就可以采用智能指针来调用对象的操作。这种方法非常灵活,充分利用了C++的多态性。因为C++中的虚函数通过指针或是引用的时候才会体现出多态性。下面是C++ Primer中列举的一个例子。
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
class Sales_base
{
public:
Sales_base(const std::string &nm=" ",double pr=0.0)
:isbn(nm),price(pr){}
Sales_base(const Sales_base &sb)
{
isbn=sb.isbn;
price=sb.price;
}
virtual ~Sales_base(){}
virtual double net_price(std::size_t n)const
{
return n*price;
}
virtual Sales_base *clone()const
{
return new Sales_base(*this);
}
const std::string &get_isbn()const
{
return isbn;
}
protected:
std::string isbn;
double price;
};
class Bulk_item : public Sales_base
{
public:
Bulk_item(const std::string &nm=" ",double pr=0.0,std::size_t min=0,double disc=0.0)
:Sales_base(nm,pr),min_qty(min),discount(disc){}
Bulk_item(const Bulk_item &bi)
:Sales_base(bi)
{
min_qty=bi.min_qty;
discount=bi.discount;
}
virtual ~Bulk_item(){}
Bulk_item *clone()const
{
return new Bulk_item(*this);
}
double net_price(std::size_t n)const
{
if(n>=min_qty)
return price*(1-discount)*n;
else
return price*n;
}
protected:
std::size_t min_qty;
double discount;
};
class Sales_item
{
public:
Sales_item()
:p(0),used(new std::size_t(1)){}
Sales_item(const Sales_item &si)
:p(si.p),used(si.used){++*used;}
Sales_item(const Sales_base &sb)
{
p=sb.clone();
used=new std::size_t(1);
}
~Sales_item(){decr_use();}
Sales_item &operator=(const Sales_item &si);
Sales_base *operator->()
{
if(p)
return p;
else
throw std::logic_error("NULL Pointer");
}
Sales_base &operator*()
{
if(p)
return *p;
else
throw std::logic_error("NULL Pointer");
}
protected:
Sales_base *p;
std::size_t *used;
void decr_use()
{
if(--*used==0)
{
delete p;
delete used;
}
}
};
Sales_item &Sales_item::operator =(const Sales_item &si)
{
decr_use();
++*si.used;
p=si.p;
used=si.used;
return *this;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<Sales_item> sv;
sv.push_back(Sales_item(Sales_base("C++ Primer",99)));
sv.push_back(Sales_item(Bulk_item("Algorithm",80,2,0.3)));
sv.push_back(Sales_item(Bulk_item("The art of programming",60,3,0.1)));
for(std::vector<Sales_item>::size_type sz=0;sz<sv.size();sz++)
{
std::cout<<"Name : "<<sv[sz]->get_isbn()<<" Price: "<<sv[sz]->net_price(1)<<std::endl;
}
return 0;
}