为什么dynamic_cast允许使用非唯一基类类型?

时间:2018-09-28 07:03:45

标签: c++

来自https://en.cppreference.com/w/cpp/language/dynamic_cast

dynamic_cast < new_type > ( expression )

  

3)如果new_type是对Base的指针或引用,而expression的类型是对Derived的指针或引用,其中Base是唯一,可访问派生基类的结果,结果是指向expression指向或标识的派生对象中基类子对象的指针或引用。 (注意:隐式转换和static_cast也可以执行此转换。)

示例代码:

#include <iostream>
using namespace std;
class A {
//public:
//  virtual ~A() {
//
//  }
};

class B : public A {

};

class C : public B {

};

class D : public B, public A {

};

int main()
{
    D* pd = new D;
    if (B* pa = dynamic_cast<B*>(pd)) {
        cout << "1";
    }
    return 0;
}

在VC ++下没有错误或警告

warning: direct base 'A' inaccessible in 'D' due to ambiguity在gcc下,link

我不应该期待编译错误吗?


现在我发现,如果尝试将D*转换为A*,将会发生错误,但是如上所述,从D*转换为B*不会出错。

int main()
{
    D* pd = new D;
    if (A* pa = dynamic_cast<A*>(pd)) {
        cout << "1";
    }
    return 0;
}

link

2 个答案:

答案 0 :(得分:3)

在这种情况下,唯一表示派生的包含 new_type一次,而不是派生的来自单个基类。

因此,在您的示例中,B是唯一的,因为D 仅包含一次

在您的示例中,D 包含 A两次(直接一次,一次通过B),因此无法强制转换为A A不是唯一的。

请注意,“包容”很重要。因此,在此示例中,C两次从Base派生,这很好,因为Base是用关键字virtual继承的:

struct Base { };
struct A: virtual Base { };
struct B: virtual Base { };
struct C: A, B { };

int main() {
    C c;
    dynamic_cast<Base &>(c);
}

(如果我没有使用过virtual,那么Base将会是模棱两可的)

注意:我会改用static_cast,因为在这种情况下它也可以执行强制转换。在这里使用dynamic_cast有点误导,因为转换将在编译时完成,而不是在运行时完成。

答案 1 :(得分:0)

警告是由多重继承模型中的间接基类问题引起的。 D具有基类A的两个副本,一个直接复制,一个通过B间接复制。将基类指定为虚拟基类(与@geza示例相同)时,虚拟基类之间仅共享一个基类数据成员的副本。

class A {
public:
    A() {}
};

class B : virtual public A {
public:
    B() : A() {}
};

class C : public B, virtual public A {
public:
    C() : B() {}
};

int main()
{
  A* pa = static_cast<A *>(new C()); // no more warning since A is virtual
  return 0;
}

在这里有很好的解释:Multiple Base Classes