![C/C++拾遗(十八):面向对象——句柄类与继承-LMLPHP C/C++拾遗(十八):面向对象——句柄类与继承-LMLPHP](https://c1.lmlphp.com/user/master/2018/10/03/db43f69d2445682946de87faeca3f320.jpg)
一、指针型句柄
其实说白了句柄类一点都不神秘,前面我们接触过“计数类”用来管理指针,这里的句柄类类似,但是比简单的计数类增加了一些其他的功能,因为我们除了利用它管理指针,还希望便捷的使用其指向的对象。这里的主要idea就是将指针的管理工作封装到一个类中,类中起码具有两个数据成员,一个指向对象的指针和一个计数指针,计数归零时意味着要释放对象和句柄类。这里我们使用的例子还是上一节中的图书类,这里简单再次给出:
点击(此处)折叠或打开
- //图书基类
- class Item_base
- {
- public:
- Item_base(const std::string &book = "",
- double sales_price = 0.0):
- book_no(book), price(sales_price) {}
- std::string book() const {return book_no;}
- virtual double net_price(std::size_t n) const
- {return n*price;}
- virtual ~Item_base() {}
- private:
- std::string book_no;
- protected:
- double price;
-
- } ;
- //含有折扣的图书类,必须满足最小的min_qyt数量要求才可以享有折扣
- class Bulk_item : public Item_base
- {
- public:
- double net_price(std::size_t) const;
- private:
- std::size_t min_qyt;
- double discount;
- }
- double Bulk_item::net_price(std::size_t cnt) const
- {
- if (cnt >= min_qty)
- return cnt * (1 - discount ) * price;
- else
- return cont * price;
- }
点击(此处)折叠或打开
- Handle_item item(Bulk_item("0-201-42778-2", 42, 2, 201));
- item->net_price() //对net_price函数的虚调用
点击(此处)折叠或打开
- //定义一个句柄类
- class Handle_item
- {
- public:
- Handle_item():p(0), cnt(new std::size_t(1)) {} //默认构造函数
- Handle_item(const Item_base&); //自定义的接受基类引用为参数,进行绑定的构造函数
- Handle_item(const Handle_item &i): //复制构造函数
- p(i.p), cnt(i.cnt) {++*cnt;}
- ~Handle_item() {des_use();} //析构函数
- Handle_item& operator=(const Handle_item); //定义赋值操作
-
- const Handle_item *oprator->()const { //定义->运算符
- if (p) return p;
- else
- throw std::logic_error("未绑定Handle_item"));
- )
- const Handle_item &operator*() const { //定义解引用运算符
- if (p) return p;
- else
- throw std::logic_error("未绑定Handle_item");
- }
- private:
- Item_base *p;
- std::size_t *cnt;
- void des_use()
- {
- if (--*cnt == 0)
- {
- delete p;
- delete cnt;
- }
- }
-
-
- }
点击(此处)折叠或打开
- Handle_item&
- Handle_item::oprator=(const Handle_item &rhs)
- {
- ++*rhs.use;
- des_use();
- p = rhs.p;
- use = rhs.use;
- return *this;
- }
实现构造函数的时候,特别说明接受Item_base引用绑定一个句柄类的构造函数,因为这里存在的问题是Item_base引用的实际对象类型只有在运行时才能够确定,那如何为其分配空间呢?解决的思路是:既然参数是动态绑定,那么我们的行为也实现动态绑定。实现动态绑定的方法自身是使用虚函数,这就需要我们定义一个新的虚函数clone(),从而能够实际的对象类型开辟合适的空间。为了使用虚函数clone(),我们为基类和派生类添加函数:
点击(此处)折叠或打开
- Item_base::
- virtual Item_base* clone() const {return new Item_base(*this);}
- Bulk_item::
- Bulk_item* clone() const {return new Bulk_item(*this);}
点击(此处)折叠或打开
- Handle_item::Handle_item(const Item_base &item):
- p(item.clone()), cnt(new std::size_t(1)) {}
二、句柄的使用
定义了handle_item,接下来使用的时候就要将句柄类对象放入multiset容器中成为容器元素,从而实现利用指针访问商品对象的最终目的。这里有一个小问题需要解决,放入multiset中的元素必须能够比价大小从而确定排列顺序,我们不会重载
点击(此处)折叠或打开
- inline bool
- compare(const Handle_item &lhs, const Handle_item &rhs)
- {
- return lhs->book() < rhs->book();
- }
点击(此处)折叠或打开
- class Basket {
- typedef bool (*comp)(const Handle_item&, const Handle_item&);
- public:
- typedef std::multiset<Handle_item, comp> set_type;
- typedef set_type::size_type size_type;
- typedef set_type::const_iterator const const_iter;
- Basket():items(compare) {}
- void add(const Handle_item &item)
- {
- items.insert(item);
- }
- size_type size(cosnt Handle_item &i)const
- {
- return items.count(i);
- }
- double total() const;
- private:
- std::multiset<Handle_item, comp> items;
- }
- double Basket::total() const
- {
- double sum = 0.0;
- for (const_iter iter = items.begin();
- iter != items.end();
- iter = items.upper_bound(*iter))
- {
- sum += (*iter)->net-price(items.count(*iter));
- }
- }
PS:
最后谈谈自己对于句柄类的感觉。句柄类听名字就让自己想到了windows中的句柄概念,记得当时看的时候也只是知道那是一个数据结构,里面肯定封装了对象的指针,但是还有更多的对象属性在里面,比如访问权限控制等等。现在想来原型结构上系统的“句柄”也许与我们变成使用的句柄类有些类似吧。