C++中的接口继承

MOn*_*DaR 17 c++ inheritance interface

我有以下类结构:

class InterfaceA
{ 
   virtual void methodA =0;
}

class ClassA : public InterfaceA
{
   void methodA();
}

class InterfaceB : public InterfaceA
{
   virtual void methodB =0;
}

class ClassAB : public ClassA, public InterfaceB
{ 
   void methodB(); 
}
Run Code Online (Sandbox Code Playgroud)

现在,以下代码无法编译:

int main()
{
    InterfaceB* test = new ClassAB();
    test->methodA();
}
Run Code Online (Sandbox Code Playgroud)

编译器说该方法methodA()是虚拟的而不是实现的.我认为它是在ClassA(实现InterfaceA)中实现的.有谁知道我的错在哪里?

lau*_*ura 22

那是因为你有两份副本InterfaceA.请参阅此更大的解释:https://isocpp.org/wiki/faq/multiple-inheritance(您的情况类似于'可怕的钻石').

virtual从InterfaceA继承ClassA时需要添加关键字.virtual从InterfaceA继承InterfaceB 时还需要添加.


Dee*_*orn 9

劳拉建议的虚拟继承当然是问题的解决方案.但它最终只有一个InterfaceA.它也有"副作用",例如.请参阅https://isocpp.org/wiki/faq/multiple-inheritance#mi-delegate-to-sister.但如果习惯它,它可能会派上用场.

如果您不想要副作用,可以使用模板:

struct InterfaceA
{ 
  virtual void methodA() = 0;
};

template<class IA>
struct ClassA : public IA //IA is expected to extend InterfaceA
{
  void methodA() { 5+1;}
};

struct InterfaceB : public InterfaceA
{
  virtual void methodB() = 0;
};

struct ClassAB 
  : public ClassA<InterfaceB>
{ 
  void methodB() {}
};

int main()
{
  InterfaceB* test = new ClassAB();
  test->methodA();
}
Run Code Online (Sandbox Code Playgroud)

所以,我们只有一个父类.

但是当有一个以上的"共享"类(InterfaceA是"共享",因为它位于"可怕的钻石"之上时,它看起来更难看,请参见https://isocpp.org/wiki/faq/multiple-inheritance由Laura发布).参见示例(如果ClassA也实现了interfaceC,那将是什么):

struct InterfaceC
{
  virtual void methodC() = 0;
};

struct InterfaceD : public InterfaceC
{
  virtual void methodD() = 0;
};

template<class IA, class IC>
struct ClassA
  : public IA //IA is expected to extend InterfaceA
  , public IC //IC is expected to extend InterfaceC
{
  void methodA() { 5+1;}
  void methodC() { 1+2; }
};

struct InterfaceB : public InterfaceA
{
  virtual void methodB() = 0;
};

struct ClassAB
  : public ClassA<InterfaceB, InterfaceC> //we had to modify existing ClassAB!
{ 
  void methodB() {}
};

struct ClassBD //new class, which needs ClassA to implement InterfaceD partially
  : public ClassA<InterfaceB, InterfaceD>
{
  void methodB() {}
  void methodD() {}
};
Run Code Online (Sandbox Code Playgroud)

不好的是,您需要修改现有的ClassAB.但你可以这样写:

template<class IA, class IC = interfaceC>
struct ClassA
Run Code Online (Sandbox Code Playgroud)

然后ClassAB保持不变:

struct ClassAB 
      : public ClassA<InterfaceB>
Run Code Online (Sandbox Code Playgroud)

并且您具有模板参数IC的默认实现.

使用哪种方式供您决定.当它很容易理解时,我更喜欢模板.养成习惯是很困难的,B :: incrementAndPrint()和C :: incrementAndPrint()会打印不同的值(不是你的例子),请看:

class A
{
public:
  void incrementAndPrint() { cout<<"A have "<<n<<endl; ++n; }

  A() : n(0) {}
private:
  int n;
};

class B
  : public virtual A
{};

class C
  : public virtual A
{};

class D
  : public B
  : public C
{
public:
  void printContents()
  {
    B::incrementAndPrint();
    C::incrementAndPrint();
  }
};

int main()
{
  D d;
  d.printContents();
}
Run Code Online (Sandbox Code Playgroud)

并输出:

A have 0
A have 1
Run Code Online (Sandbox Code Playgroud)


And*_*ndy 6

之所以存在这个问题,是因为 C++ 并没有真正的接口,只有具有多重继承的纯虚拟类。编译器不知道在哪里找到 的实现,methodA()因为它是由 的不同基类实现的ClassAB。您可以通过实现methodA()inClassAB()来调用基本实现来解决此问题:

class ClassAB : public ClassA, public InterfaceB
{ 
    void methodA()
    {
        ClassA::methodA();
    }

    void methodB(); 
}
Run Code Online (Sandbox Code Playgroud)