【问题标题】:C++: using a base class as the implementation of an interfaceC++:使用基类作为接口的实现
【发布时间】:2010-09-10 16:00:40
【问题描述】:

在 C++ 中是否可以使用另一个基类在派生类中提供接口(即抽象基类)的实现?

class Base
{
    virtual void myfunction() {/*...*/};
}
class Interface
{
    virtual void myfunction() = 0;
}
class Derived
    : public Base, public Interface
{
    // myfunction is implemented by base
}

以上内容应该可以编译,但实际上并不能正常工作。有没有办法达到这个效果?

万一有人关心,想要这样做的原因是(对于我的应用程序)使用来自另一个项目/命名空间的通用库来在我的项目中提供接口的实现是有意义的。我可以把所有东西都包装起来,但这似乎需要很多额外的开销。

谢谢。

【问题讨论】:

  • 也许如果Base继承自Interface...
  • @djeidot: InterfaceDerived 属于应用程序,Base 属于库。在很多情况下,人们不想与库共享接口——只重用实现来支持应用程序特定的接口。 ObjC 的特性(以及许多其他语言),但不适用于 C++。

标签: c++ inheritance


【解决方案1】:

如果Base 不是从Interface 派生的,那么您必须在Derived 中转接呼叫。在您必须编写额外代码的意义上,这只是“开销”。我怀疑优化器会让它像您最初的想法一样有效。

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

class Base {
    public:
        virtual void myfunction() {/*...*/}
};

class Derived : public Interface, public Base {
    public:
        void myfunction() { Base::myfunction(); }  // forwarding call
};

int main() {
   Derived d;
   d.myfunction();
   return 0;
}

【讨论】:

  • 这就是我猜我最终不得不做的事情。我是否必须明确转发它,或者有没有办法使用 using 指令实现相同的目标? (例如使用 Base::myfunction();)。这行得通吗?
  • 有谁知道优化器是否真的会同样有效?我在 Fedora 13 上使用 gcc 4.5.1。
  • Base::myfunction() 不必是virtual,无论如何它都是静态调用的。此外,从Base 私下继承可能是一个想法,因为这是一个实现细节,而不是“is-a”关系。
  • (更好的是支持组合而不是继承)
  • A using declaration (using Base::myfunction;) 不起作用,Derived 将保持抽象。这是因为Derived 包含Interface::myfunction()Base::myfunction()Base::myfunction 是公开的,你是公开继承的,所以 using 声明不会改变任何东西。
【解决方案2】:

试试这个:

class Interface
{
    virtual void myfunction() = 0;
}
class Base : public Interface
{
    virtual void myfunction() {/*...*/};
}
class Derived
    : public Base
{
    // myfunction is implemented by base
}

【讨论】:

  • 当然,这是首选方式。然而,OP 说他想“使用来自另一个项目/命名空间的通用库来提供我项目中接口的实现”。因此我认为他不能从 Interface 派生 Base。
  • 我可以做到这一点,因为我控制了这两个库并且我考虑过,但从设计角度来看,这对我来说并没有什么意义。其他库没有理由实现这个接口,我认为它会混淆库的其他用户。
【解决方案3】:

没有。 (反正不是这样)

您可能会被其他语言(如 Java、C#、ActionScript 等)的处理方式误导。

在 C++ 中,多重继承和虚拟类的管理方式使得接口(在其他语言中使用)过时了。在那些其他语言中,接口用于解决由于缺少多重继承而引发的问题(好坏,这是一种选择)。

所以如果你想做的只是提供一个通用接口和一些提供默认实现的虚拟方法,只需在基类中实现:

class Interface
{
    virtual void myfunction() { /*...*/ } //default implementation
    virtual void yourFunction()  = 0 ; // this one HAVE TO be implemented by the user
};
class Derived
    : public Interface // don't need another class
{
    // myfunction is implemented by base
    void yourFunction(); // have to implement yourFunction
};
class DerivedB
    : public Interface // don't need another class
{
    void myFunction(); // myfunction is implemented by base but we implement it for this specific class
    void yourFunction(); // have to implement yourFunction
};

但是,如果您想提供多个具有相同接口的基类,则认为您的接口类是其他类的基类

// in this order
class Interface
{
    virtual void myfunction() = 0;
};
class BaseA : public Interface
{   
    // here "virtual" is optional as if the parent is virtual, the child is virtual too
    virtual void myfunction() {/*...*/}; // BaseA specific implementation
};
class BaseB : public Interface
{
    virtual void myfunction() {/*...*/}; // BaseB specific implementation
};

然而,有一种不太容易阅读(阅读:不推荐)的方式来提供默认实现,但强制用户明确说明他是否想使用它。它利用了这样一个事实,即即使是纯虚函数也可以具有可以调用的默认实现:

class Interface
{
    virtual void myfunction() { /*...*/ } // default implementation
    virtual void yourFunction()  = 0 ; // this one HAVE TO be implemented by the user BUT provide a default implementation!
};

// in Interface.cpp 

void Interface::yourFunction() // default implementation of the virtual pure function
{ /*...*/ }

// in Derived.h

class DerivedA
    : public Interface // don't need another class
{
    // myfunction is implemented by base
    void yourFunction(); // have to implement yourFunction -- DerivedA specific
};

class DerivedB
    : public Interface // don't need another class
{
    void myFunction(); // myfunction is implemented by base but we implement it for this specific class
    void yourFunction() { Interface::yourFunction(); } // uses default implementation of yourFunction, hidden but existing
};

但不要这样做。

【讨论】:

  • 你说得对,我最初是根据我在 Java 和 C# 方面的经验提出这个想法,但后来意识到同样的事情在 C++ 中行不通。我不确定我认为这是好是坏,如果它有效肯定会更容易,但我知道它没有一个很好的理由。
  • 与以前的语言相比,您有更多选择,但这也会给您带来更多后果。我会是你,唯一的问题是:我会提供多个默认实现吗?如果不是,请使用第一个简单的解决方案(只需在非纯虚函数中定义默认实现);否则,您需要一个“概念层次结构”,由您的类层次结构表示为第二个示例。
  • 虽然这是最完整的答案,但我认为这是 C++ 处理此问题的方式中的一个错误和/或虚拟方法链接方式的设计选择不佳。我将首先说明我是一名现在使用 C++ 工作的 Java 开发人员,但我认为这个类层次结构是有效的,应该可以工作,而无需手动将接口方法转发给父级。接口 IA 在抽象类 AbstractA 中实现,并由 IB 扩展。 C 类扩展了 AbstractA 并实现了 IB,它现在必须将 IA 方法转发给 AbstractA 实现,即使方法信号相同。
【解决方案4】:

Base 和 Interface 是完全不同的类型。编译器应该如何知道“myfunction”是相关的?您必须在 Derived 中实现它,即使该实现仅调用 Base 版本。

【讨论】:

    【解决方案5】:

    响应假设派生类希望成为CONCRETE 类或非抽象类,即希望能够实例化'Derived'. 类型的对象。我还在回复中假设了公共成员函数。

    没有。派生类必须实现它从所有基类继承的所有纯虚函数。在这种情况下,'Base::myfunction' 虽然由'Derived' 继承,但不会被视为'Derived::myfunction' 的实现

    'Derived::myfunction' 仍然需要提供'Interface::myfunction'. 的实现

    一种可能是'Derived::myfunction' 可以在内部委托给'Base::myfunction'

    但是,如果不希望 Derived 成为一个具体的类(我怀疑这是 OP 的意图),那么上述类的安排是好的(从语言的角度来看)

    【讨论】:

      猜你喜欢
      • 2016-07-22
      • 2013-09-30
      • 1970-01-01
      • 2010-09-22
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      相关资源
      最近更新 更多