[英]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.