c++设计:继承和返回不透明句柄

c++ design: inheritance and returning opaque handles

本文关键字:返回 不透明 句柄 继承 设计 c++      更新时间:2023-10-16

我有两个像这样的接口:

class IThing {
    ...
    virtual IHandle* getHandle(void) = 0;
    virtual void useHandle(IHandle *handle) = 0;
};
class IHandle { ... }

我希望用户能够实现IThing和IHandle。例如,如果用户创建了MyThingMyHandle,那么getHandle应该返回一个指向MyHandle的指针,用户可以稍后在useHandle中使用该指针。

这将工作,但我不喜欢这个设计,因为IHandle的多个实现可以在IThing的实现之间混淆。同样在useHandle中,用户需要显式地向下转换到他们的IHandle实现。是否有更类型安全的方法来做到这一点?

我不太确定你想设计什么。但这里有一些想法,我希望能有所帮助。

基本原则是,从IThing公开派生的类确实是IThing。所以你可以用IThing做的所有事情,你也可以用MyThing做,包括获得IHandle

没有设计问题,只要你的IHandle衍生品都遵守相同的原则。这意味着你的东西不应该对特定的手柄做任何假设,反之亦然。

然而,如果你在MyHandle的实现中使用它与MyThing相关联的假设(反之亦然),你将陷入你所描述的麻烦。实际上,您使用的是类定义中没有表示的依赖项。所以,是的,你必须使用下cast。它让人不舒服,因为它暴露了一个设计问题。

由于您的类是多态的,您可以通过使用dynamic_cast检查nullptr来限制向下转换风险。但这是一种变通方法,而不是设计改进。

或者你可以考虑模板。它们可以帮助您在编译时链接相关类型。您将获得类型安全性,但将失去运行时多态性的一些灵活性。一个示例方法:

template <class IH>
class IThing  {   
public:
    virtual IH* getHandle(void) =0;
    virtual void useHandle(IH *handle) =0;
};
class MyHandle {  };  // to keep it simple, 
class MyThing: public IThing<MyHandle> {}; // instantiation with specific handle
int main() {
    MyThing i; 
    MyHandle *h;
    h = i.getHandle(); 
    ...
 }

本例中的约束是,您不能使用不同的句柄混合不同的IThings