在 C++ 中处理类?

Posted

技术标签:

【中文标题】在 C++ 中处理类?【英文标题】:Handle class in C++? 【发布时间】:2012-09-07 13:47:59 【问题描述】:

在 C++ 入门 15.8 中,当作者谈到“句柄类和继承”时,他说:

C++ 中的一个常用技术是定义一个所谓的封面或句柄类。句柄类存储和管理指向基类的指针。该指针指向的对象的类型会有所不同;它可以指向基类或派生类对象。用户通过句柄访问继承层次结构的操作。因为句柄使用它的指针来执行这些操作,所以虚拟成员的行为在运行时会根据句柄实际绑定的对象的类型而有所不同。句柄的用户因此获得了动态行为,但他们自己不必担心管理指针。

上面的内容听起来很像我的智能指针。但是,这个“句柄”的用法有点不同。

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

句柄的后一种实现(如下所示)证明了作者在句柄上的cmets:

我们希望我们的句柄的用户创建他们自己的对象,他们可以附加一个句柄。 句柄将分配适当类型的新对象并将用户的对象复制到新分配的对象中。这样,句柄类将拥有该对象,并且可以保证在附加到对象的最后一个句柄消失之前不会删除该对象。

代码:

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 中句柄的典型含义吗?我认为句柄可以只是一个基本类型的智能指针,它在内部保持使用计数,或者更一般地说是一些魔法 int 类型,系统知道它指向什么以及如何处理它。为什么这里的句柄需要将用户对象复制到自己,然后根据副本进行使用计数?

【问题讨论】:

【参考方案1】:

现代 C++ 中的惯用等价物是:

std::shared_ptr<Base> hstd::make_shared<Derived>();

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

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

【讨论】:

谢谢,ecatmur。我的问题与为什么根本需要对象的副本(存储在 Base *p 中)有关。为什么不能像智能指针那样只让句柄接受从“新”返回的基指针,并且只跟踪使用计数。我了解“克隆”的工作方式类似于与类型无关的虚拟构造函数。 @user1559625 clone 有一些开销,但它比传递原始分配的指针更安全。 shared_ptr 使用 make_shared 来避免原始分配的指针,但它仅在 C++11 之后才可行(它使用右值引用完美转发和可变参数模板)。

以上是关于在 C++ 中处理类?的主要内容,如果未能解决你的问题,请参考以下文章

处理类 new 和 delete 运算符 C++ 中的内存泄漏

C++ 从事件处理程序中获取数据并传递给另一个类的方法?

[c++]第八章概念题 | 异常

C++“处理多个基类的虚拟函数”

编译器对C++类提前声明的处理

求C++图像处理的程序