简体   繁体   English

C ++中的接口继承

[英]Interface Inheritance in C++

I have the following class structure: 我有以下类结构:

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

Now the following code is not compilable: 现在,以下代码无法编译:

int main()
{
    InterfaceB* test = new ClassAB();
    test->methodA();
}

The compiler says that the method methodA() is virtual and not implemented. 编译器说方法methodA()是虚拟的而不是实现的。 I thought that it is implemented in ClassA (which implements the InterfaceA ). 我认为它是在ClassA (实现InterfaceA )中实现的。 Does anyone know where my fault is? 有谁知道我的错在哪里?

That is because you have two copies of InterfaceA . 那是因为你有两个InterfaceA副本。 See this for a bigger explanation: https://isocpp.org/wiki/faq/multiple-inheritance (your situation is similar to 'the dreaded diamond'). 请参阅此更大的解释: https//isocpp.org/wiki/faq/multiple-inheritance (您的情况类似于'可怕的钻石')。

You need to add the keyword virtual when you inherit ClassA from InterfaceA. 从InterfaceA继承ClassA时,需要添加关键字virtual You also need to add virtual when you inherit InterfaceB from InterfaceA. 从InterfaceA继承InterfaceB时,还需要添加virtual

Virtual inheritance, which Laura suggested, is, of course, the solution of the problem. 劳拉建议的虚拟继承当然是问题的解决方案。 But it doesn't end up in having only one InterfaceA. 但它最终只有一个InterfaceA。 It has "side-effects" too, for ex. 它也有“副作用”,例如。 see https://isocpp.org/wiki/faq/multiple-inheritance#mi-delegate-to-sister . 请参阅https://isocpp.org/wiki/faq/multiple-inheritance#mi-delegate-to-sister But if get used to it, it may come in handy. 但如果习惯它,它可能会派上用场。

If you don't want side effects, you may use template: 如果您不想要副作用,可以使用模板:

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

So, we are having exactly one parent class. 所以,我们只有一个父类。

But it looks more ugly when there is more than one "shared" class (InterfaceA is "shared", because it is on top of "dreaded diamond", see here https://isocpp.org/wiki/faq/multiple-inheritance as posted by Laura). 但是当有一个以上的“共享”类(InterfaceA是“共享”,因为它位于“可怕的钻石”之上时,它看起来更难看,请参见https://isocpp.org/wiki/faq/multiple-inheritance由Laura发布)。 See example (what will be, if ClassA implements interfaceC too): 参见示例(如果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() {}
};

The bad thing, that you needed to modify existing ClassAB. 不好的是,您需要修改现有的ClassAB。 But you can write: 但你可以这样写:

template<class IA, class IC = interfaceC>
struct ClassA

Then ClassAB stays unchanged: 然后ClassAB保持不变:

struct ClassAB 
      : public ClassA<InterfaceB>

And you have default implementation for template parameter IC. 并且您具有模板参数IC的默认实现。

Which way to use is for you to decide. 使用哪种方式供您决定。 I prefer template, when it is simple to understand. 我更喜欢模板,当它很容易理解时。 It is quite difficult to get into habit, that B::incrementAndPrint() and C::incrementAndPrint() will print different values (not your example), see this: 养成习惯是很困难的,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();
}

And the output: 并输出:

A have 0
A have 1

This problem exists because C++ doesn't really have interfaces, only pure virtual classes with multiple inheritance. 存在这个问题是因为C ++实际上没有接口,只有具有多重继承的纯虚拟类。 The compiler doesn't know where to find the implementation of methodA() because it is implemented by a different base class of ClassAB . 编译器不知道在哪里找到methodA()的实现,因为它是由不同的ClassAB基类ClassAB You can get around this by implementing methodA() in ClassAB() to call the base implementation: 您可以通过实现解决这个问题methodA()ClassAB()调用基实现:

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

    void methodB(); 
}

You have a dreaded diamond here. 你这里有一颗可怕的钻石。 InterfaceB and ClassA must virtually inherit from InterfaceA Otherwise you ClassAB has two copies of MethodA one of which is still pure virtual. InterfaceB和ClassA实际上必须从InterfaceA继承,否则您的ClassAB有两个MethodA副本,其中一个仍然是纯虚拟的。 You should not be able to instantiate this class. 您不应该能够实例化此类。 And even if you were - compiler would not be able to decide which MethodA to call. 即使你是 - 编译器也无法决定调用哪个MethodA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM