[英]C++ multiple inheritance with base classes deriving from the same class
在嘗試重用不同類的代碼時,我偶然發現了一個問題。 我在這里發帖,希望你們中的一些人能夠幫助我。
我有一組派生自同一個類(A)的類(B,C),這些類強制執行某些方法(foo,run)。 B類實現了這些方法,B和C都提供了其他方法:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
現在,我想要做的是從B和C繼承,以便我可以擁有額外的方法(foobar,bar),但也不必從A類(foo)實現該方法,因為它已經在B中定義:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
但由於某種原因,編譯器給了我這個錯誤:
test.cpp:在函數'int main(int,char **)'中:test.cpp:68:35:error:無法分配抽象類型'D <float,double>'的對象
一個<float,double> * d = new D <float,double>(); // 我需要做什么
test.cpp:48:11:注意:因為以下虛函數在'D <float,double>'中是純粹的:
D類:公共B <I,O>,公共C <I,O,int> {
^
test.cpp:9:22:注意:void一個<I,O> :: foo()const [with I = float; O =雙]
virtual void foo()const = 0; //強制執行此功能
這是我用來運行它的代碼:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
我想從指向A的指針使用D類對象的'run'函數。由於所有函數都是虛函數,我希望執行在最低繼承點中定義的每個函數的實現,這意味着'B :: run '將被丟棄。 由於'D :: run'使用來自B和CI的函數,因此需要從這兩個類繼承。
我希望我已經足夠描述它並且不會混淆任何人。 謝謝您的幫助!
如果將B
和C
更改為從A
模板類虛擬繼承,則它們將在由D
組合時共享單個基本實例,並且此錯誤將消失:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
然而,這種模式(稱為鑽石繼承(反)模式)可能很難推理,我強烈建議盡可能避免使用它。 您可能會在以后遇到更加模糊的問題。
以下是此技術的一個示例,但顯示了一些乍看之下可能無法預料到的結果:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
請注意,即使您正在調用C::foo()
,它是純虛擬的,因為只有一個A
實例,繼承的純虛函數通過共享的A
vtable解析為B::foo()
。 這是一個有點令人驚訝的副作用 - 您可以最終調用在表兄弟類型上實現的方法。
@cdhowie的答案為您提供了解決方案。
要理解編譯器抱怨的問題,請使用一組更簡單的類:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
D
的類層次結構是:
A A
| |
B C
\ /
D
使用此繼承結構, D
有兩個虛擬表,一個對應於B
繼承層次結構,另一個對應於C
繼承層次結構。 不同之處在於,在B
層次結構中,存在A::foo()
的實現,而C
層次結構中沒有一個。
假設您被允許構造D
類型的對象。
D d;
C* cp = &d;
現在cp
指向D
的C
層次結構,並使用未實現foo
的虛擬表。 這將是編譯器在編譯時幫助您避免的運行時錯誤。
我知道這是一個遲到的答案,但由於你是從C類的純虛函數派生出來的,你必須實現它,然后在那些函數中調用基類:
virtual void foo() const { // for class C
B::foo();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.