你可以合法地dynamic_cast到多态类的非多态基类

Sir*_*Guy 16 c++ polymorphism casting

这个答案中,出现了以下情况:

#include <cassert>

struct A {};

struct B { virtual ~B(){} };

struct AA{};
template <class T>
struct C : A, T {};

int main()
{
  B * b = new C<B>;
  AA * aa = new C<AA>;
  assert(dynamic_cast<A*>(b));
  assert(dynamic_cast<A*>(aa)); //this line doesn't compile, as expected
}
Run Code Online (Sandbox Code Playgroud)

在g ++ 4.8.4(Ubuntu)上,这个编译并且断言传递.我的问题是,这真的合法吗?我觉得你根本不应该dynamic_cast参加一个非多态的课程,但我承认我不是这里发生的事情的专家.

当我尝试相反的方向时:

dynamic_cast<B*>((A*)(new C<B>));
Run Code Online (Sandbox Code Playgroud)

它无法编译,声明"源类型不是多态的".我觉得这是一个线索,但它仍然似乎是一个延伸,找到属于当前指针是基础的类的非多态基类(这个句子是否有意义?).

Chr*_*ckl 13

是的你可以.

正如C++标准在§5.2.7/ 5中所说的那样dynamic_cast<T>(v):

如果T是"指向cv1的 指针B"并且v具有类型"指向cv2的 指针D",这 B是一个基类D,则结果是指向由其指向BD对象的唯一子对象的指针v.

给出了一个例子:

struct B { };
struct D : B { };
void foo(D* dp) {
  B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}
Run Code Online (Sandbox Code Playgroud)

如您所见,多态类显然不是dynamic_cast标准允许的唯一用例.

顺便一句,cppreference 用较少的标准语言解释它:

如果new_type是Base的指针或引用,并且expression的类型 是Derived的指针或引用,其中Base是Derived的唯一可访问基类,结果是Derived中Base类子对象的指针或引用通过表达指出或识别的对象.(注意:隐式转换和static_cast也可以执行此转换.)