• 智能指针与句柄类(四)


      当我们希望使用容器来保存继承体系中的对象时,容器用于继承体系中的类型会有影响:派生类对象复制到基类对象时,派生类对象将被切掉。那么解决这一问题的方法通常是使用容器保存基类对象的指针,这些指针实际指向的是程序运行时动态分配的派生类对象,用户必须保证在容器析构前调用delete来释放动态分配的对象,如下例:

     1 class Base
     2 {
     3 public:
     4     virtual void action() = 0;
     5 };
     6 class Derived1 : public Base
     7 {...};
     8 class Derived2 : public Base
     9 {...};
    10 class Derived3 : public Base
    11 {...};
    12 
    13 void fun()
    14 {
    15     vector<Base*> v;
    16 
    17     v.push_back(new Derived1);
    18     v.push_back(new Derived2);
    19     v.push_back(new Derived3);
    20 
    21     for(int i=0; i!=v.size(); i++)
    22         v[i]->action();
    23         
    24     for(int i=0; i!=v.size(); i++)
    25         delete v[i];
    26     
    27     return;
    28 }

      我们可以使容器保存之前定义的Handle类对象,Handle类对象管理继承层次中的对象指针,对其生命周期进行控制,而不用再结束时手动释放动态分配的内存。

    1 vector<Handle<Base> > vh;
    2 vh.push_back(new Derived1);
    3 vh.push_back(new Derived2);
    4 vh.push_back(new Derived3);
    5 
    6 for(int i=0; i!=vh.size(); i++)
    7     vh[i]->action();

      在《C++ Primer》中,容器类保存句柄类,句柄类封装之前定义的Handle类对象,并通过Handle类对象对指针进行管理与计数,控制复制、赋值以及指针的释放。以<<C++Primer>>中的继承层次为例:

     1 class Item_Base
     2 {
     3 public:
     4     //...constructor...
     5     virtual Item_Base* clone()const {return new Item_Base(*this)}
     6 
     7     virtual double net_price(size_t) const;
     8     virtual ~Item_Base(){}
     9 private:
    10     string isbn;
    11 protected:
    12     double price;
    13 };
    14 
    15 class Bulk_item : public Item_Base
    16 {
    17 public:
    18     //...constructor...
    19     virtual Bulk_item* clone()const {return new Bulk_item(*this)}
    20 
    21     double net_price(size_t) const;
    22 private:
    23     size_t min_qty;
    24     double discount;
    25 };
    26 
    27 class Disc_item : public Item_Base
    28 {
    29 public:
    30     //...constructor...
    31     virtual Disc_item* clone()const {return new Disc_item(*this)}
    32 
    33     double net_price(size_t)const;
    34 private:
    35     size_t quantity;
    36 };

      clone虚函数进行复制,对于派生类的返回类型必须与基类实例的返回类型完全匹配的要求,有一个例外:如果虚函数的基类实例返回类类型的引用或指针,则该虚函数的派生类实例可以返回基类实例返回的类型的派生类(或者是类类型的指针或引用)。有了clone函数的定义,对于句柄类的构造函数就很简单了:

     1 class Sales_item
     2 {
     3 public:
     4     Sales_item():h(){}
     5     Sales_item(const Item_Base &item):h(item.clone()) {}
     6     const Item_Base & operator*() const{return *h}
     7     const Item_Base * operator->() const {return h.operator->}
     8 private:
     9     Handle<Item_Base> h;
    10 };

      这种方式进行处理时,客户代码段甚至不需要进行new操作,所有的分配和释放都在Sales_item内部完成。

    1 vector<Sales_item> vItem;
    2 vItem.push_back(Disc_Item());
    3 vItem.push_back(Bulk_item());
  • 相关阅读:
    linux杂记
    mysql 备份命令
    查看mysql 套接字文件 mysql.sock
    处理下载是文件名乱码正确姿势
    对象创建完成后进行数据同步
    python——数据库编程
    python——网络编程2
    python——网络编程
    python——12、面向对象
    pythoning——11、正则匹配
  • 原文地址:https://www.cnblogs.com/Tour/p/4158977.html
Copyright © 2020-2023  润新知