使用多重继承实现虚方法是一种好习惯吗?

时间:2014-08-20 13:29:06

标签: c++ multiple-inheritance virtual-inheritance idiomatic

我有:

class A {
    virtual void foo() = 0;
    virtual void bar() = 0;
};

class Fooing {
    virtual void foo() = 0;
};

class Barring {
    virtual void bar() = 0;
};

class TallFooing : public Fooing {
    void foo(){ std::cout << "tall foo" << std::endl; }
};

class ShortFooing : public Fooing {
    void foo(){ std::cout << "short foo" << std::endl; }
};

class BlueBarring : public Barring {
    void bar() { std::cout << "blue bar" << std::endl; }
};

class RedBarring : public Barring {
    void bar() { std::cout << "red bar" << std::endl; }
};

template <typename S, typename T>
class B : public A, public S, public T { };

int main() {
    A* a1 = new B<TallFooing, RedBarring>();
    A* a2 = new B<ShortFooing, BlueBarring>();

    a1->foo(); a1->bar();
    a1->foo(); a2->bar();
};

在Barring课程中混合使用“好主意”(TM)?我做得对吗?如果没有,你能否建议做同样的替代/改进?

另外,以下内容如下:

class Fooing {
    virtual void foo() = 0;
};

class Barring {
    virtual void bar() = 0;
};
class A : public virtual Fooing, public virtual Barring { };


class TallFooing : public Fooing {
    void foo(){ std::cout << "tall foo" << std::endl; }
};

class ShortFooing : public Fooing {
    void foo(){ std::cout << "short foo" << std::endl; }
};

class BlueBarring : public Barring {
    void bar() { std::cout << "blue bar" << std::endl; }
};

class RedBarring : public Barring {
    void bar() { std::cout << "red bar" << std::endl; }
};

template <typename S, typename T>
class B : public virtual A, public S, public T { };

main()相同?

备注:

  • foo()bar()确实是独立的,任何组合都可以。也就是说,什么都不会破坏。

2 个答案:

答案 0 :(得分:1)

您的代码无法编译(即使我修复了语法错误)。 B的实例化是抽象的,因为它们派生自A,它具有纯虚函数并且不实现它们。来自一个父级的同名函数不实现另一个父级的纯虚函数。

您可以使用您的模板方法在A中实现B(为简洁起见,我使用struct,您的代码尝试访问类外的私有成员):

template<class S, class T>
struct B: A, S, T {
    void foo() {
        this->S::foo();
    }
    void bar() {
        this->T::bar();
    }
};

或许更常见的方法是使用虚拟继承。根据其他接口定义A可能是有意义的:

struct A: virtual Fooing, virtual Barring {

注意虚拟的使用。这将为您提供评论中提到的钻石。为了使编译器在单独的接口中建立foo之间的连接,这是必要的。您还必须在所有实现类中进行虚拟继承:

struct TallFooing: virtual Fooing {

这些更改应该使您的代码编译。多个/虚拟继承是一个好主意是非常基于意见。将它用于纯虚拟接口以外的任何东西通常都是不受欢迎的。

另外,请将接口类的析构函数设为private或将其声明为virtual。否则你可能最终会泄漏代码(编译器可能会注意到这一点)。

答案 1 :(得分:0)

我修复了所有可能的编译错误(缺少包含,缺少public),但是子类B 仍然没有补充{{1}和A::foo所以即使这样程序也无法编译。你不能在C ++中使用多重继承来以这种方式实现抽象接口。