多重继承和多态问题

Ada*_*zyk 11 c++ multiple-inheritance

考虑这个C++代码:

#include <iostream>
using namespace std;

struct B {
    virtual int f() { return 1; }
    int g() { return 2; }
};
struct D1 : public B { // (*)
    int g() { return 3; }
};
struct D2 : public B { // (*)
    virtual int f() { return 4; }
};
struct M : public D1, public D2 {
    int g() { return 5; }
};

int main() {
    M m;
    D1* d1 = &m;
    cout << d1->f()
         << static_cast<D2&>(m).g()
         << static_cast<B*>(d1)->g()
         << m.g();
}
Run Code Online (Sandbox Code Playgroud)

它打印1225.如果我们进行虚拟继承,即在标有(*)的行virtual之前添加public,则打印4225.

  1. 你能解释一下为什么要1改变4吗?
  2. 你能解释一下static_cast<D2&>(m)和的含义static_cast<B*>(d1)吗?
  3. 你怎么不迷失在这种组合中?你在画东西吗?
  4. 在普通项目中发现这种复杂的设置是否常见?

Who*_*aig 5

图片胜于雄辩,所以在答案之前......


M类层次结构没有 D1和D2的B的虚拟基础继承:

    M
   / \
  D1 D2
  |   |
  B   B
Run Code Online (Sandbox Code Playgroud)

M级层级WITH B中D1和D2的虚拟基础继承:

    M
   / \
  D1 D2
   \ /
    B
Run Code Online (Sandbox Code Playgroud)
  1. 跨代委托,或者我喜欢称之为兄弟 - 多态性与扭曲.虚基础继承将B :: f()重写修复为D2:f().希望在考虑虚拟函数的实现位置以及它们因继承链而重写的内容时,图片可以帮助解释这一点.

  2. static_cast在这种情况下,运算符用法驱动从派生到基类类型的转换.

  3. 阅读非常糟糕的代码并了解语言"工作"的基础知识的经验很多

  4. 谢天谢地.这并不常见.然而,原来的iostream库会给你做噩梦,如果这总是令人困惑的话.


iam*_*ind 2

(1) 你能解释一下为什么1变成4吗?

没有virtual继承,有2个独立的继承层次;B->D1->MB->D2->M。想象一下 2 个virtual函数表(尽管这是实现定义的)。
当您调用f()with时D1*,它只会知道B::f(),仅此而已。通过virtual继承,baseclass B被委托给M,因此D2::f()被视为 的一部分class M

static_cast<D2&>(m)(2) 你能解释一下和的含义static_cast<B*>(d1)吗?

static_cast<D2&>(m),就像考虑class Mas的对象一样class D2
static_cast<B*>(d1),就像考虑class D1as的指针一样class B1
两者都是有效的演员表。
因为函数选择g()不是在编译时发生的。如果是这样的话,所有这些选角都不再重要了。virtualvirtual

(3) 你如何在这种组合中不迷失方向?你在画东西吗?

当然,它很复杂,乍一看,如果有这么多这样的类,人们可能很容易迷失。

(4) 在正常项目中,这样复杂的设置是否常见?

一点也不,这很不寻常,有时还有代码味道。