处理比较:空类与未定义类相比无效*

Naw*_*waz 10 c++ handles incomplete-type empty-class

Microsoft的GDI +定义了许多在内部被视为句柄的空类.例如,(来源GdiPlusGpStubs.h)

//Approach 1

class GpGraphics {};

class GpBrush {};
class GpTexture : public GpBrush {};
class GpSolidFill : public GpBrush {};
class GpLineGradient : public GpBrush {};
class GpPathGradient : public GpBrush {};
class GpHatch : public GpBrush {};

class GpPen {};
class GpCustomLineCap {};
Run Code Online (Sandbox Code Playgroud)

还有其他两种方法来定义句柄.他们是,

//Approach 2
class BOOK;  //no need to define it!
typedef BOOK *PBOOK;
typedef PBOOK HBOOK; //handle to be used internally

//Approach 3
typedef void* PVOID;
typedef PVOID HBOOK; //handle to be used internally
Run Code Online (Sandbox Code Playgroud)

我只想知道每种方法的优点和缺点.

微软方法的一个优点是,他们可以使用空类定义句柄的类型安全 层次结构,我认为这是其他两种方法无法实现的,但我想知道这种层次结构对实现有什么好处?无论如何,还有什么?

编辑:

第二种方法(即使用不完整的类)的一个优点是我们可以防止客户端解除引用句柄(这意味着,这种方法似乎强烈支持封装,我想).如果尝试取消引用句柄,代码甚至不会编译.还有什么?

与第三种方法相同的优点是,您不能取消引用句柄.

Öö *_*iib 3

方法 #1 是 C 风格和 C++ 接口之间的某种中间方式。您必须将句柄作为参数传递,而不是成员函数。暴露多态性的优点是可以减少接口中函数的数量,并在编译时检查类型。通常大多数专家更喜欢 pimpl idiom(有时称为编译防火墙)而不是这样的接口。您不能使用方法 #1 与 C 交互,因此最好使用完整的 C++。

方法#2 是C 风格封装和信息隐藏。该指针可能(并且通常是)指向真实事物的指针,因此它没有被过度设计。库的用户不能取消引用该指针。缺点是它没有暴露任何多态性。优点是您可以在与用 C 编写的模块交互时使用它。

方法 #3 是过度抽象的 C 风格封装。该指针可能实际上根本不是指针,因为库的用户不应强制转换、释放或取消引用它。优点是它可能会携带异常或错误值,缺点是大部分必须在运行时进行检查。

我同意 DeadMG 的观点,即语言中立的面向对象的接口在 C++ 中使用起来非常简单和优雅,但这些也涉及比编译时检查更多的运行时检查,并且当我不需要与其他语言交互时就太过分了。因此,如果仅是 C++ 时需要与 C 或 Pimpl 惯用语交互,我个人更喜欢方法 #2。