C ++多重继承,其基类派生自同一个类

时间:2014-09-05 15:53:36

标签: c++ inheritance abstract

我在尝试重用不同类的代码时偶然发现了一个问题。我在这里发帖,希望你们中的一些人能够帮助我。

我有一组派生自同一个类(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:错误:无法分配抽象类型的对象'D&lt; float,double&gt;'

     
    

A&lt; float,double&gt; * d = new D&lt; float,double&gt;(); //我需要做什么

  
     

test.cpp:48:11:注意:因为以下虚函数在'D&lt; float,double&gt;'中是纯粹的:

     
    

D类:公共B&lt; I,O&gt;,公共C&lt; I,O,int&gt; {

    ^
  
     

test.cpp:9:22:注意:void A&lt; I,O&gt; :: 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和C中的函数,我需要继承这两个类。

我希望我已经足够描述并且没有让任何人感到困惑。 谢谢你的帮助!

3 个答案:

答案 0 :(得分:6)

如果您将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实例,继承的纯虚函数会解析为B::foo(),但共享{{1} vtable。这是一个有点令人惊讶的副作用 - 您可以最终调用在表兄弟类型上实现的方法。

答案 1 :(得分:2)

@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指向C的{​​{1}}层次结构,并使用未实现D的虚拟表。这将是编译器在编译时帮助您避免的运行时错误。

答案 2 :(得分:0)

我知道这是一个迟到的答案,但由于你是从C类的纯虚函数派生出来的,你必须实现它,然后在那些函数中调用基类:

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