【问题标题】:C++: Derived + Base class implement a single interface?C ++:派生+基类实现单个接口?
【发布时间】:2010-09-22 09:34:24
【问题描述】:

在 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 解决了这个问题,但想知道是否有更好的方法。

【问题讨论】:

    标签: c++ class inheritance interface


    【解决方案1】:

    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 放在派生的成员函数前面,这些函数在基类中是虚拟的,即使不是严格要求也是如此。

    【讨论】:

    • 如果你这样做,那么你不需要BaseFunction的第二个声明。
    • 这是他写的。我不想改变它。他可能有理由那样做
    • 没问题,我只是不想让他或其他人经历永恒,认为这是必要的。 :)
    • 2 个问题: - 现在 BASE 不能自己实例化。 - 从 base 派生的其他类现在必须实现 DerivedFunction class OtherDerived : public Base { public: void OtherDerivedFunction(){} };
    • 我编辑了代码。我不是故意放 BaseFunction 的第二个声明
    【解决方案2】:

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

    【讨论】:

    • 嗯.. 没有.... 再次检查代码。 Base 不继承自 Interface。 (接口有DervicFunction,Base中没有实现)
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      我同意 litb 的回答。不过,这里有机会了解一些虚函数和多重继承的工作原理。

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

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

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

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

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

      【讨论】:

        【解决方案5】:

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

        但是,由于某种原因,我一直限制自己进行编译时检查。这个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 中不需要传递函数,每个人都很高兴。当然,它不再是严格意义上的接口,但没关系。为什么我没有早点想到呢? :)

        【讨论】:

        • 没问题。您只需从 DerivedInterface 和 BaseInterface 派生一个类,然后您就可以在原始问题中获得“Interface”类的接口
        • 无论如何。永远不要像那样使用 dynamic_cast :) dynamic_cast 应该是解决通过设计正确接口无法解决的问题的最后手段。在你的情况下,只需按照我在上面的评论中所说的做接口,然后你就可以做 BaseInterface* baseInterface = &derived;并调用两者:)
        • 是的,这将给我相同的界面,但不同的实现,这就是重点。我有一个基类和派生类的实现,我需要它们的单个接口。这听起来就像我会得到的一样接近。
        • 等等,我指的是你的“both”类,它定义了自己的实现。嗯。
        猜你喜欢
        • 2013-09-30
        • 1970-01-01
        • 2014-06-17
        • 2012-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多