簡體   English   中英

C ++多重繼承,其基類派生自同一個類

[英]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的函數,因此需要從這兩個類繼承。

我希望我已經足夠描述它並且不會混淆任何人。 謝謝您的幫助!

如果將BC更改為從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指向DC層次結構,並使用未實現foo的虛擬表。 這將是編譯器在編譯時幫助您避免的運行時錯誤。

我知道這是一個遲到的答案,但由於你是從C類的純虛函數派生出來的,你必須實現它,然后在那些函數中調用基類:

virtual void foo() const {      // for class C  
    B::foo();
}

暫無
暫無

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

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