【问题标题】:Is it good practice to implement virtual methods using multiple inheritance? [duplicate]使用多重继承实现虚拟方法是一种好习惯吗? [复制]
【发布时间】:2014-10-13 21:21:13
【问题描述】:

我有:

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() 确实是独立的,任何组合都可以。也就是说,什么都不会损坏。

【问题讨论】:

  • 如果 A 实现了bar(),编译器会将a1-&gt;bar() 之类的调用视为模棱两可,因为您真的要调用谁的bar()?这就是钻石问题,您可以使用像您这样的方法来跳线。
  • @AndyG:注意我的编辑。
  • 我的评论仍然有效。另外,我认为您在TallFooingShortFooing 中有错字(应该分别是TallFooShortFoo
  • 那些告诉你不要对这样的接口使用多重继承,然后告诉你在Java中使用接口的人,可以放心地忽略。另外,我没有在你的遗产中看到任何钻石。但是,我确实看到了一个类 B,它继承了两个名为 foo() 的函数(一个来自 A,一个来自 S),这令人困惑,甚至可能无法编译。你应该避免混淆!
  • 编写无法编译的代码不是一个好主意。请提出可以做的事情,然后问是否应该做。

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


【解决方案1】:

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

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

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 {

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

struct TallFooing: virtual Fooing {

这些更改应该可以编译您的代码。多重/虚拟继承是否是一个好主意很大程度上取决于意见。将它用于纯虚拟接口以外的任何东西通常都会受到反对。

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-23
      • 2011-02-08
      • 2015-01-08
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 2017-06-30
      • 2014-04-03
      相关资源
      最近更新 更多