防止在C ++中对抽象类接口进行子类化

时间:2015-01-05 14:37:08

标签: c++ interface subclassing restriction

我向用户提供了一个SDK,允许他们用C ++编写DLL来扩展软件。

SDK标头主要包含接口类定义。这些类有两种类型:

  • 用户必须子类化并实现的一些
  • 一些是核心类的包装器,由应用程序传递给DLL函数作为指针,然后可以通过DLL代码用作调用核心函数的参数。这些接口不应该被用户子类化并传递给核心函数,因为它们需要特定的核心子类。

我在手册中编写了不应该被子类化的接口,并且只能通过应用程序提供的对象上的指针来使用。但是在某些地方,如果你不阅读手册,那么在SDK中将它们子类化是很诱人的。

是否可以阻止对SDK标头中的某些接口进行子类化?

2 个答案:

答案 0 :(得分:0)

只要客户端不需要使用指针即可 将它传回你的DLL,你可以使用前向声明; 你不能从一个不完整的类型派生出来。 (面对类似的时候 最近的情况,我去了整个猪,并设计了一个特殊的包装类型 基于void*。接口代码中有很多内容,但是 除了将值传递回去之外,客户端无法做很多事情 我。)

如果有问题的类实现了客户端必须的接口 也用,有两种解决方案。首先是改变这个, 用自由函数替换每个成员函数 指向该类型的指针,只提供一个前向声明。该 第二是使用类似的东西:

class InternallyVisibleInterface;

class ClientVisibleInterface
{
private:
    virtual void doSomething() = 0;
    ClientVisibleInterface() = default;
    friend class InternallyVisibleInterface;
protected:      //  Or public, depending on whether the client should
                //  be able to delete instances or not.
    virtual ~ClientVisibleInterface() = default;
public:
    void something();
};

并在你的DLL中:

class InternallyVisibleInterface : public ClientVisibleInterface
{
protected:
    InternallyVisibleInterface() {}

    //  And anything else you need.  If there is only one class in
    //  your application which should derive from the interface,
    //  this is it.  If there are several, they should derive from
    //  this class, rather than ClientVisibleInterface, since this
    //  is the only class which can construct the
    //  ClientVisibleInterface base class.
};

void ClientVisibleInterface::something()
{
    assert( dynamic_cast<InternallyVisibleInterface*>( this ) != nullptr );
    doSomething();
}

这提供了两个级别的保护:第一,虽然派生 直接来自ClientVisibleInterface是可能的,这是不可能的 结果类有一个构造函数,所以它不能 实例化。其次,如果客户端代码以某种方式作弊, 如果他这样做会有运行时错误。

你可能不需要同时保护;一个或另一个应该 满足。私有构造函数将导致编译时错误, 而不是运行时的。另一方面,如果没有它,你就不会 甚至不得不提到InternallyVisibleInterface的名字 分布式标题。

答案 1 :(得分:0)

一旦开发人员拥有开发环境,他几乎可以做任何事情,你甚至不应该试图控制它。

恕我直言,你可以做的最好的事情是确定核心应用程序和扩展DLL之间的限制,并确保从那些 或正确的类中获取的对象,如果它们是中断消息则中止不是。

使用RTTI和typeid通常不赞成,因为它通常是糟糕的OOP设计的标志:在普通用例中,调用虚方法足以调用适当的代码。但我认为在您的使用案例中可以安全地考虑它。