C++句柄解析

C++句柄类解析

  引题:在C++中,对于运行时类型识别问题。在程序中使用引用或者指针在运行时动态识别对象类型。然而使用指针或者引用却增加了用户负担(在继承体系中,没有明确的基类到派生类的转换,必须用户显示转换并将结果对象加入容器中。但是这样的做法结果却是派生对象部分成员是未初始化的)。

对于这一问题,可以将对象指针 保存在容器中来解决。但此时,用户必须明确容器中指针和 对象的同步性(不能只有指针而对象不存在或者收指针不存在,对象存在)。

更好的解决方案就是句柄类了:

  C++ 中一个通用的技术是定义包装(cover)类或句柄类。句柄类存储和管 理基类指针。指针所指对象的类型可以变化,它既可以指向基类类型对象又可以 指向派生类型对象。用户通过句柄类访问继承层次的操作。因为句柄类使用指针 执行操作,虚成员的行为将在运行时根据句柄实际绑定的对象的类型而变化。因 此,句柄的用户可以获得动态行为但无须操心指针的管理。

  包装了继承层次的句柄有两个重要的设计考虑因素:

  • 对任何保存指针的类一样,必须确定对复制控制做些什 么。包装了继承层次的句柄通常表现得像一个智能指针 或者像一个值。
  • 句柄类决定句柄接口屏蔽还是不屏蔽继承层次,如果不屏蔽继承层次,用 户必须了解和使用基本层次中的对象。

①指针型句柄:

  句柄包装指针,用户可以将该句柄类当作指针使用,却不用去管理指针指向的对象。(句柄类更像是一个中介控制者)

定义方案:

1. 使用类包装指针,包装计数器(每个对象都有各自的这两个成员)

2.使用类包装指针,包装计数器指针(资源和计数器共享)

句柄类除了定义构造,拷贝构造,赋值,还需要定义引用,解引用(使之看起来更像是指针)

对于构造函数:

1个默认构造函数初始化成员为0;

1个构造函数声明指定对象类型的句柄。

那么问题来了,如果用户并不知晓用 继承体系中具体哪个层次对象进行初始化,如何做呢。

解决这个问题的通用方法是定义虚操作进行复制,我们称将 该操作命名为 clone。(克隆):

  对于继承层次中的每个类,增加一个虚克隆函数eg:

class Item_base 
{
 public: 
    virtual Item_base* clone() const 
    { 
        return new Item_base(*this);
     }
 };    

有了克隆函数那么 句柄类的定义如下:

Sales_item::Sales_item(const Item_base &item):
    p(item.clone()), use(new std::size_t(1)) 
{ }

对于继承层次中  如果需要逻辑比较函数,一个好的做法是 定义内部比较,比较内部核心成员。

inline bool
compare(const Sales_item &lhs, const Sales_item &rhs)
{
    return lhs->book() < rhs->book();
}

使用带关联容器的比较器

要有效地工作,关联容器需要对每个操作使用同一比较函数。然而,期望用 户每次记住比较函数是不合理的,尤其是,没有办法检查每个调用使用同一比较 函数。因此,容器记住比较函数是有意义的。通过将比较器存储在容器对象中, 可以保证比较元素的每个操作将一致地进行。

这种做法,实质上就是使用函数指针,函数回调实现真正的比较。

// type of the comparison function used to order the multiset

typedef bool (*Comp)(const Sales_item&, const Sales_item&);

关联容器的每个构造函数使我们能够提供比较函数的名 字。可以这样定义使用 compare 函数的空 multiset:

std::multiset<Sales_item, Comp>  items(compare);

multiset 是STL中的联合容器。。在头文件<set>中,具体用法请参看《STL源码剖析》

参考(C++primer)

原文地址:https://www.cnblogs.com/lang5230/p/5060574.html