用C++处理身体习语

Handle Body Idiom in C++

本文关键字:习语 处理 C++      更新时间:2023-10-16

我的库中有一个类,我想向用户公开它。我不想公开整个类,因为我以后可能想进行二进制不兼容的更改。我不知道以下哪种方式最好。

案例1:

struct Impl1;
struct Handle1
{
// The definition will not be inline and will be defined in a C file
// Showing here for simplicity
void interface()
{
static_cast<Impl1*>(this)->interface();
}
}
struct Impl1 : public Handle1
{
void interface(){ /* Do ***actual*** work */ }
private:
int _data; // And other private data
};

案例2:

struct Impl2
struct Handle2
{
// Constructor/destructor to manage impl
void interface() // Will not be inline as above.
{
_impl->interface();
}
private:
Impl2* _impl;
}
struct Impl2
{
void interface(){ /* Do ***actual*** work */ }
private:
int _data; // And other private data
};

Handle类仅用于公开功能。它们将仅在库中创建和管理。继承只是为了抽象实现细节。不会有多个/不同的impl类。就性能而言,我认为两者将完全相同。是吗?我正在考虑采用案例1的方法。有什么问题需要解决吗?

您的第二种方法看起来非常像编译防火墙习惯用法(有时称为PIMPL习惯用法)。

唯一的区别是,在编译防火墙习惯用法中,实现类通常(但并不总是)被定义为成员。别忘了构造函数(分配Impl)和析构函数(释放它)。以及复制构造函数和赋值运算符。

第一种方法也适用,但它需要工厂函数来创建对象。当我使用它时,我只需将Handle中的所有函数都设置为纯虚拟函数,并让客户端代码直接调用它们。

在这种情况下,由于客户端代码实际上有指向对象的指针(在编译防火墙习惯用法中,唯一的指针在Handle类本身中),客户端将不得不担心内存管理;如果没有循环是可能的,这是shared_ptr非常有意义的一种情况。(出厂功能可以返回例如,shared_ptr和客户端代码可能永远看不到原始指针。)