C++中面向对象编程的一个颇具讽刺意味的地方是,不能使用对象支持面向对象编程,相反必须使用指针或者引用。C++中的多态性:动态绑定必须使用基类的指针或者引用调用虚函数来进行。 或者说STL容器来存储继承层次的对象,派生类对象复制给基类对象会被截断为基类对象,不能将基类对象复制给派生类对象,STL容器最好是存储对象的指针。所以具有继承层次的对象,在C++中程序中更多的使用对象的指针。
但使用指针又会加重用户的负担,特别是类中存在指针成员时,因为类的复制控制,很容易导致以下问题:
1. 多个类的对象中的指针是指针的同一块内存,存在一个修改,全部受影响的情况,容易造成程序的逻辑错误;
2. 很可能在某处删除了指针对象,而其他地方认为指针对象还存在,继续访问指针指向的对象,访问悬空指针的结果很随机,容易造成严重的运行时错误
而智能指针是C++中常见的使用指针方式,可以有效的解决悬垂指针的问题。句柄类就是封装了继承层次类的智能指针。句柄类存储和管理基类指针。指针说指对象的类型可以变化,它既可以指向基类类型对象又可以指向派生类型对象,用户通过句柄类访问继承层次操作。句柄的用户可以获得动态行为但无须操心指针的管理。
包装了继承层次的句柄有两个重要的设计考虑因素:
1. 必须确定对复制控制怎么处理,句柄通常表现的像一个智能指针或者像一个值一样
2. 句柄类决定句柄接口还是不是屏蔽继承层次,如果不屏蔽继承层次,用户必须了解和使用基本层次中的对象。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <list>
#include <string>
#include <vector>
#include <set>
#include<utility>
#include<functional>
#include<stdexcept>
//base class
class Item_base
{
friend std::ostream& operator<<(std::ostream &, Item_base &);
public:
Item_base(const std::string& book="",double sale_price=0.0):isbn(book),price(sale_price) {}
std::string book() const { return isbn;}
virtual Item_base* clone() const
{
return new Item_base(*this);
}
virtual double net_price(std::size_t n) const
{
return price*n;
}
//debug function controlled by flag parameter
virtual void debug1(bool flag) const
{
if(flag)
std::cout<<"ISBN: "<<isbn<<std::endl
<<"Price: "<<price<<std::endl;
}
//debug function controlled by flag member
virtual void debug2() const
{
if(flag)
std::cout<<"ISBN: "<<isbn<<std::endl
<<"Price: "<<price<<std::endl;
}
virtual ~Item_base() {}
protected:
double price; // price of a book
bool flag;
private:
std::string isbn; // isbn of a book
};
std::ostream& operator<<(std::ostream & os,Item_base& ib)
{
os<<"\tUsing operator<<(std::ostream &,Item_base&);"<<std::endl
<<"\tVisit Item_base's book():\t"<<ib.isbn<<std::endl
<<"\tVisit Item_base's net_price():"
<<"3 "<<ib.book()<<" , the price is:\t"
<<ib.net_price(3)<<std::endl;
return os;
}
//derived class
class Bult_Item :public Item_base
{
friend std::ostream & operator<<(std::ostream & ,Bult_Item &);
public:
Bult_Item(const std::string& book="",double sale_price=0.0,std::size_t qty=0,double disc=0.0):Item_base(book,sale_price),min_qty(qty),discount(disc) {}
Bult_Item* clone() const
{
return new Bult_Item(*this);
}
double net_price(std::size_t cnt) const
{
if(cnt > min_qty)
return cnt*(1-discount)*price;
}
void debug1(bool flag) const
{
if(flag)
std::cout<<"ISBN: "<<book()<<std::endl
<<"PriceL "<<price<<std::endl
<<"Min_quantiry: "<<min_qty<<std::endl
<<"Discount Rate: "<<discount<<std::endl;
}
void debug2() const
{
if(flag)
std::cout<<"ISBN: "<<book()<<std::endl
<<"PriceL "<<price<<std::endl
<<"Min_quantiry: "<<min_qty<<std::endl
<<"Discount Rate: "<<discount<<std::endl;
}
~Bult_Item() {}
private:
std::size_t min_qty; // min quantity of books to have a discount
double discount; //discount rate
};
std::ostream & operator<<(std::ostream & os,Bult_Item & bi)
{
os<<"\tUsing operator<<(std::ostream &,Bulk_Item);"<<std::endl
<<"\tVisit Item_base's book():\t"<<bi.book()<<std::endl
<<"\tVisit Item_base's net_price():"
<<"5 "<<bi.book()<<" , the price is:\t"
<<bi.net_price(5)<<std::endl;
return os;
}
//handle class
class Sales_item
{
public:
//default constructor:unbound handle
Sales_item():p(0),use( new std::size_t(1)) {}
//attaches a handle to copy of the Item_base object
Sales_item(const Item_base & item):p(item.clone()),use(new std::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& operator=(const Sales_item&);
~Sales_item() { decr_use();}
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");
}
private:
Item_base *p; //pointer to shared item
std::size_t * use ; // pointer to a shared use count( reference count);
void decr_use()
{
if(--*use == 0)
{
delete p;
delete use;
}
}
};
Sales_item& Sales_item::operator=(const Sales_item& rhs)
{
++*rhs.use;
decr_use();
p = rhs.p;
use = rhs.use;
return * this;
}
//compare function of Sales_Item for multiset to use
inline bool compare(const Sales_item& rh1,const Sales_item& rh2)
{
return rh1->book() < rh2->book() ;
}
//really class used in real business
class Basket
{
typedef bool (*Comp) (const Sales_item&,const Sales_item&);
public:
typedef std::multiset<Sales_item,Comp> set_type;
typedef set_type::size_type size_type;
typedef set_type::const_iterator const_iter;
//constructor
Basket():items(compare) {}
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;
private:
std::multiset<Sales_item,Comp> items;
};
double Basket::total() const
{
double sum = 0.0;
for(const_iter i = items.begin() ; i != items.end() ; i = items.upper_bound(*i))
{
sum += (*i)->net_price(items.count(*i));
}
return sum;
}
//test code
int main()
{
return 0;
}
示例代码地址:
https://github.com/QiJunHu/learningRecord/blob/master/learningC%2B%2B/learningHandleClass.cpp