句柄比较:空类vs.未定义类vs. void * [英] Handles Comparison: empty classes vs. undefined classes vs. void*

查看:213
本文介绍了句柄比较:空类vs.未定义类vs. void *的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  //方法1 

类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 {};

还有其他两种方法来定义句柄。

  //方法2 
class BOOK; //不需要定义它!
typedef BOOK * PBOOK;
typedef PBOOK HBOOK; //内部使用的句柄

//方法3
typedef void * PVOID;
typedef PVOID HBOOK; //内部使用的句柄

我只想知道每个方法的优点和缺点。



Microsoft的方法的一个优点是,他们可以使用空类来定义类型安全 ,这(我认为)是不可能与其他两种方法,虽然我不知道这种层次结构将带来实现的优势?



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



与第三种方法同样的优点,你不能取消引用句柄。

解决方案

方法#1是C风格和C ++界面之间的一个中间。而不是成员函数,你必须传递句柄作为参数。暴露的多态性的优点是可以减少接口中的函数的数量,并且类型被检查编译时间。通常大多数专家喜欢pimpl成语(有时称为编译防火墙)这样的接口。你不能使用方法#1与C接口,所以最好去完整的C ++。



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



方法3是过抽象的C风格封装。指针可能真的不是一个指针,因为库的用户不应该转换,释放或解引用它。优点是它可能会携带异常或错误值,缺点是大多数都需要检查运行时间。



我同意DeadMG的语言中性object-面向对象的接口是非常容易和优雅的使用C ++,但这些也涉及更多的运行时检查,而不是编译时间检查,当我不需要与其他语言接口时是过度的。所以我个人喜欢方法#2,如果它需要接口C或Pimpl的成语,当它是只有C ++。


Microsoft's GDI+ defines many empty classes to be treated as handles internally. For example, (source 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 {};

There are other two ways to define handles. They're,

//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

I just want to know the advantages and disadvantages of each of these approaches.

One advantage with Microsoft's approach is that, they can define type-safe hierarchy of handles using empty classes, which (I think) is not possible with the other two approaches, though I wonder what advantages this hierarchy would bring to the implementation? Anyway, what else?

EDIT:

One advantage with the second approach (i.e using incomplete classes) is that we can prevent clients from dereferencing the handles (that means, this approach appears to support encapsulation strongly, I suppose). The code would not even compile if one attempts to dereference handles. What else?

The same advantage one has with third approach as well, that you cannot dereference the handles.

解决方案

Approach #1 is some mid-way between C style and C++ interface. Instead of member functions you have to pass the handle as argument. The advantage of exposed polymorphism is that you can reduce the amount of functions in interface and the types are checked compile time. Usually most experts prefer pimpl idiom (sometimes called compilation firewall) to such interface. You can not use approach #1 to interface with C so better go full C++.

Approach #2 is C style encapsulation and information hiding. The pointer may be (and often is) a pointer to real thing, so it is not over-engineered. User of library may not dereference that pointer. Disadvantage is that it does not expose any polymorphism. Advantage is that you may use it when interfacing with modules written in C.

Approach #3 is over-abstracted C-style encapsulation. The pointer may be really not a pointer at all since user of library should not cast, deallocate or dereference it. Advantage is that it may so carry exception or error values, disadvantage is that most of it has to be checked run time.

I agree with DeadMG that language-neutral object-oriented interfaces are very easy and elegant to use from C++, but these also involve more run-time checks than compile time checks and are overkill when i don't need to interface with other languages. So i personally prefer Approach #2 if it needs to interface with C or Pimpl idiom when it is C++ only.

这篇关于句柄比较:空类vs.未定义类vs. void *的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆