2012-09-07 178 views
4

在C++ primer 15.8中,当作者谈论'句柄类和继承'时,他说:在C++中处理类?

'C++中常见的技术是定义一个所谓的覆盖或句柄类。句柄类存储和管理指向基类的指针。该指针指向的对象的类型将有所不同;它可以指向基类或派生类型的对象。用户通过句柄访问继承层次结构的操作。由于句柄使用其指针来执行这些操作,因此虚拟成员的行为在运行时会有所不同,具体取决于句柄实际绑定到的对象的类型。句柄的用户因此获得动态行为,但本身不必担心管理指针。

以上听起来很像一个智能指针给我。但是,这个'处理'的用法有一点不同。

Handle h(Derived()); // noticed a derived object, not a pointer is used to initialize the handle! 
h->func(); 

和后实现手柄(如下图所示)的证明了我把手上的笔者点评:我们想”我们的手柄来创建自己的对象的用户,他们可以附加手柄。 手柄将分配适当类型的新对象,并复制用户的对象成新分配的对象。这样,手柄类将拥有该对象,可以保证对象不会被删除,直到附着在物体上的最后一个句柄消失。”

public: 
    Base(){} 
    virtual int func(std::size_t n) const {} 
    virtual Base* clone() const { return new Base(*this); } 
}; 

class Derived : public Base { 
public: 
    Derived():Base(){} 
    int func(std::size_t) const; // redefine 
    Derived* clone() const { return new Derived(*this); } 
}; 

class Handle { 
public: 
    Handle(const Base &b):p(b.clone()), use(new std::size_t(1)) { } 
private: 
    Base *p; 
    std::size_t *use; // pointer to shared use count 
}; 

我的问题是:这真的是C++或OO中句柄的典型含义吗?我认为这个句柄可以只是一个基本类型的智能指针,它在内部保留use-count,或者更普遍的是一些神奇的int类型,系统知道它指向什么以及如何处理它。为什么这里的句柄需要将用户对象拷贝到自身,然后根据拷贝进行使用计数?

任何人都可以帮助?

感谢,

回答

4

在现代C++的惯用等效是:

std::shared_ptr<Base> h{std::make_shared<Derived>()}; 

一般来说,“处理”意味着某种形式的类型擦除,使代码处理句柄不需要知道功能如何实现的细节。

的原因,你已经证明使用clone复制对象的代码正是为了执行类型擦除;在clone方法被调用的时候,Derived对象的实际类型的知识被删除。就实现质量而言,代码是非线程安全的,这与传统C++无关,但是对于具有线程感知内存模型的现代C++来说是个问题。它也并不明显是异常安全的;将例外安全委派给标准库类如shared_ptr要好得多。最后,Base类缺少虚拟析构函数。

+0

谢谢,ecatmur。我的问题更多地涉及为什么COPY的对象(存储在Base * p中)完全需要。为什么不能让句柄接受从'new'返回的基指针,就像智能​​指针会做的一样,并且只跟踪use-count。我理解'克隆'就像一个独立于类型的虚拟构造函数。 – user1559625

+0

@ user1559625'clone'有一些开销,但比传递原始分配的指针更安全。 'shared_ptr'使用'make_shared'来避免原始分配的指针,但它只能在C++ 11(它使用右值引用的完美转发和可变参数模板)之后才可行。 – ecatmur