12

在 C++ 中,是否可以让基类和派生类实现单个接口?

例如:

class Interface
{
    public:
        virtual void BaseFunction() = 0;
        virtual void DerivedFunction() = 0;
};

class Base
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public Base, public Interface
{
    public: 
        void DerivedFunction(){}
};

void main()
{
    Derived derived;
}

这失败了,因为 Derived 无法实例化。就编译器而言,从未定义过 Interface::BaseFunction。

到目前为止,我发现的唯一解决方案是在 Derived 中声明一个传递函数

class Derived : public Base, public Interface
{
    public: 
        void DerivedFunction(){}
        void BaseFunction(){ Base::BaseFunction(); }
};

有没有更好的解决方案?


编辑:如果重要的话,这是我在使用 MFC 对话框时遇到的一个现实问题。

我有一个从 CDialog 派生的对话框类(可以说是 MyDialog)。由于依赖问题,我需要创建一个抽象接口(MyDialogInterface)。使用 MyDialogInterface 的类需要使用 MyDialog 特有的方法,但也需要调用 CDialog::SetParent。我刚刚通过创建 MyDialog::SetParent 并将其传递给 CDialog::SetParent 来解决它,但想知道是否有更好的方法。

4

5 回答 5

17

C++ 没有注意到从 Base 继承的函数已经实现BaseFunction:该函数必须在派生自Interface. 以这种方式更改它:

class Interface
{
    public:
        virtual void BaseFunction() = 0;
        virtual void DerivedFunction() = 0;
};

class Base : public Interface
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public Base
{
    public: 
        virtual void DerivedFunction(){}
};

int main()
{
    Derived derived;
}

如果您希望能够只实现其中一个,请拆分Interface为两个接口:

class DerivedInterface
{
    public:
        virtual void DerivedFunction() = 0;
};

class BaseInterface
{
    public:
        virtual void BaseFunction() = 0;
};

class Base : public BaseInterface
{
    public:
        virtual void BaseFunction(){}
};

class Derived : public DerivedInterface
{
    public: 
        virtual void DerivedFunction(){}
};  

class Both : public DerivedInterface, public Base {
    public: 
        virtual void DerivedFunction(){}
};

int main()
{
    Derived derived;
    Base base;
    Both both;
}

注意:main 必须返回 int
注意:最好virtual将派生的成员函数放在基类中的虚拟成员函数的前面,即使不是严格要求也是如此。

于 2008-11-14T18:14:03.437 回答
4

看起来 Derived “is-a” Base 的情况并非如此,这表明包含可能是比继承更好的实现。

此外,您的 Derived 成员函数也应该被标记为虚拟函数。

class Contained
{
    public:
        void containedFunction() {}
};

class Derived
{
    public:
        virtual void derivedFunction() {}
        virtual void containedFunction() {return contained.containedFunction();}
    private:
        Containted contained;
};

如果要隐藏实现细节,可以使包含的成员成为引用或智能指针。

于 2008-11-14T18:40:38.157 回答
1

问题是,在您的示例中,您有两个实现Interface,一个来自Base,一个来自Derived。这是 C++ 语言的设计。正如已经指出的,只需Interface删除Derived.

于 2008-11-14T18:16:12.997 回答
1

我同意 litb 的回答。但是,这里有机会了解一些虚函数和多重继承是如何工作的。

当一个类有多个基类时,每个基类都有单独的 vtable。Derived将具有如下所示的 vtable 结构:

Derived
 vtable: Interface
   BaseFunction*
   DerivedFunction*
 vtable: Base
   BaseFunction*

此外,每个基类只能看到自己的 vtable。当Base被实例化时,它填充Base::BaseFunction了vtable中的指针,但是看不到Interface的vtable。

如果您提供的代码可以编译,则生成的实例的 vtable 结构Derived将如下所示:

Derived
 vtable: Interface
   BaseFunction* = 0
   DerivedFunction* = Derived::DerivedFunction
 vtable: Base
   BaseFunction* = Base::BaseFunction
于 2008-11-14T20:53:22.947 回答
0

我发现 litb 的回答缺少一件事。如果我有一个Derived实例,我可以得到一个DerivedInterfaceand BaseInterface。但是,如果我只有一个,DerivedInterface我就无法得到一个BaseInterface,因为派生DerivedInterfaceBaseInterface将不起作用。

但是,由于某种原因,我一直在限制自己进行编译时间检查。这DerivedInterface很好用:

class DerivedInterface
{
    public:
        virtual void DerivedFunction() = 0;
        BaseInterface* GetBaseInterface()
            {return dynamic_cast<BaseInterface*>(this);}
};

void main()
{
    Derived derived;

    DerivedInterface* derivedInterface = &derived;
    derivedInterface->GetBaseInterface()->BaseFunction();
}

Derived 中不需要传递函数,每个人都很高兴。当然,它不再是严格意义上的接口,但没关系。为什么我没有早点想到呢?:)

于 2008-11-15T01:57:41.910 回答