簡體   English   中英

C ++中的接口繼承

[英]Interface Inheritance in C++

我有以下類結構:

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

現在,以下代碼無法編譯:

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

編譯器說方法methodA()是虛擬的而不是實現的。 我認為它是在ClassA (實現InterfaceA )中實現的。 有誰知道我的錯在哪里?

那是因為你有兩個InterfaceA副本。 請參閱此更大的解釋: https//isocpp.org/wiki/faq/multiple-inheritance (您的情況類似於'可怕的鑽石')。

從InterfaceA繼承ClassA時,需要添加關鍵字virtual 從InterfaceA繼承InterfaceB時,還需要添加virtual

勞拉建議的虛擬繼承當然是問題的解決方案。 但它最終只有一個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();
}

所以,我們只有一個父類。

但是當有一個以上的“共享”類(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() {}
};

不好的是,您需要修改現有的ClassAB。 但你可以這樣寫:

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

然后ClassAB保持不變:

struct ClassAB 
      : public ClassA<InterfaceB>

並且您具有模板參數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();
}

並輸出:

A have 0
A have 1

存在這個問題是因為C ++實際上沒有接口,只有具有多重繼承的純虛擬類。 編譯器不知道在哪里找到methodA()的實現,因為它是由不同的ClassAB基類ClassAB 您可以通過實現解決這個問題methodA()ClassAB()調用基實現:

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

    void methodB(); 
}

你這里有一顆可怕的鑽石。 InterfaceB和ClassA實際上必須從InterfaceA繼承,否則您的ClassAB有兩個MethodA副本,其中一個仍然是純虛擬的。 您不應該能夠實例化此類。 即使你是 - 編譯器也無法決定調用哪個MethodA。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM