C ++,钻石继承,何时/什么时候需要实现纯虚拟?

时间:2011-09-16 15:34:05

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

C ++:我有一个带有纯虚函数f()的基类A,然后两个类B和C几乎从A继承,一个D继承自B和C(典型的钻石结构):< / p>

   A f() = 0
 v/ \v
 B   C
  \ /
   D

在下列情况下,f()= 0的位置和时间需要实现?

  1. B和C都有纯虚函数( - &gt;抽象类必须实现继承的纯虚函数吗?)
  2. 其中只有一个(B XOR C)有一个纯虚函数( - &gt;其他是否必须实现f()?)
  3. B和C都没有自己的纯虚拟( - &gt;可能的方式跳过B和C中的实现并将其“传递”到D?)
  4. 上述三种情况中的哪一种D需要实现f()?在哪些情况下,D可选择实现f()?在哪些情况下,如果有的话,D不可能实现f()?
  5. 对于这类问题还有其他共同建议吗?

    感谢。

4 个答案:

答案 0 :(得分:1)

  

B和C都有纯虚函数( - &gt;抽象类必须实现继承的纯虚函数吗?)

D 必须实施 ALL 继承的纯虚函数。
除非类实现类的所有纯虚函数,否则它从类本身actas派生为Abstract类。

  

其中只有一个(B XOR C)有一个纯虚函数( - &gt;另一个还必须实现f()吗?)

D必须实现它通过任何层次结构中的Base类继承的纯虚函数。如果它的直接Base类没有定义Pure虚函数,那么该类也成为一个Abstract类,除非D实现继承的纯虚函数,否则它也将变为Abstract。

  

B和C都没有自己的纯虚拟( - &gt;可能的方法来跳过B和C中的implmentation并将其“传递”到D?)

D必须实现它通过A->B&amp;继承的纯虚函数。 A-C。请注意,在这种情况下,BC都是抽象类。

  

上述三种情况中的哪一种D需要实现f()?在哪些情况下,它可以选择D来实现f()?在哪些情况下,如果有的话,D不可能实现f()?

D需要在上述所有3个条件中实现foo(),才能实现(非抽象)。

结论:

  1. 一个类需要实现它从所有它的基类继承的所有纯虚函数,否则将使该类成为一个抽象类。
  2. 继承虚拟属性,如果超类声明了一个虚拟函数,那么派生类中的重写函数也是虚拟的,它将虚拟属性传递给从中派生的所有类。

  3. 避免死亡之钻!除非你真的了解它涉及的微妙之处。很多人尝试使用虚拟继承,但这并不是实现其设计想要实现的最简单的方法。在某些情况下,虚拟继承的使用确实是必要的,但它仍然是语言提供的重要构造,但更常用于错误的方式。因此,重新访问您的设计一次以验证您是否确实需要虚拟继承是有意义的。

    以下可能是一个很好的阅读:

    1. Multiple Inheritance - Part I
    2. Multiple Inheritance - Part II
    3. Multiple Inheritance - Part III

答案 1 :(得分:0)

  

B和C都有纯虚函数( - &gt;抽象类必须实现继承的纯虚函数吗?

是。从抽象类继承的任何类必须实现虚函数才能实例化。否则它们也会是抽象的。

  

其中只有一个(B XOR C)有一个纯虚函数( - &gt;另一个还必须实现f()吗?)

由于C也来自A,因此它也应该实现f()

  

B和C都没有自己的纯虚拟( - &gt;可能的方法来跳过B和C中的implmentation并将其“传递”到D?)

你可以做到这一点。但这会阻止单独BC的实例化,例如 -

A *obj = new B(); // Error
A *obj = new C(); // Error
  

上述三种情况中的哪一种D需要实现f()?在哪些情况下,它可以选择D来实现f()?在哪些情况下,如果有的话,D是不可能实现f()?

f()可以单独在D中实现,只要您确实希望其所有父类都是抽象的。

答案 2 :(得分:0)

唯一的要求是在“叶子”级别(派生的最多)一切都有一个实现(可能只有一个实现,否则如果你访问图表的点 - 可能会产生歧义 - 在相同的“距离”。

所以D必须实现尚未实现的所有内容,或者所有内容都通过不同的路径实现了多次(消除歧义)。 如果某些东西-at D level-仍然没有实现... D不能被实例化,并且要求实现和E,从D派生。

- 钻石是永恒的 -

答案 3 :(得分:0)

  1. 不,抽象类(可能是BC)不需要实现继承的纯虚拟。像D这样的子类需要这样做才能实例化。

  2. 不,再次BC将继承纯虚方法,只需重写它就可以生成最终的具体类。

  3. 是的,这会以两种方式之一将实施传递给D。如果BC都是虚拟继承,那么D会实现一次。如果它们没有虚拟继承,则D需要覆盖两个 BC版本的f具体。

  4. 如果D是抽象的,则永远不需要实现f。假设您的意思是具体,在所有三种情况下,您都需要覆盖f中的D。仅当BC覆盖fD不需要时才会这样做。

  5. 仔细观察您的设计并删除钻石继承。在大多数情况下,这是防止所有这些问题的最佳选择。