在 C++ 中,为什么转换为派生类型的引用有效?

In C++, why does casting to reference of derived type work?

确切地说,为什么在下面的程序中 B b = (B&) a 可以编译和工作而 B b = (B) a 不能?

#include <iostream>
using namespace std;

class A {public: void f(){ cout<<"A"<<endl;} };

class B : public A { public: void f(){cout<<"B"<<endl;} };

void g(A a){  B b = (B&) a; b.f(); }

int main() {
    B b; g(b);
    return 0;
}

关于转换为派生类型的引用是否有我在这里遗漏的内容?如果我只是转换为 B,它会给出一个编译时错误,即构造函数 B(A a) 不存在。

因为从AB的隐式转换不存在,而且你也没有定义显式。

另一方面,引用转换是有效的,因为它允许用于继承类型。更准确地说,您可以在同一继承层次结构中的不同 class 之间进行双向转换。指针也是如此。相关概念称为 多态性,如果您需要一些指导以进一步研究。

但是请注意,只有 类型 B 的对象才能转换为 B 才有意义。例如:

B b;
A& aRef = B; // equivalent of A& ref = (A&)B;
B& bRef = (B&)aRef;

一旦您尝试访问 A 中不存在的 B 的某些数据或方法,您所做的操作将在 运行 时失败。因为你的实际对象是A,而不是B.

向上转型(从后代到上升)总是安全的,因为 class 的任何对象继承基数 class 一个有效的基数目的。然而,由于我在上面解释的确切原因,向下转型是危险的,并且永远不应该使用 C 风格的转型来完成。相反,使用 dynamic_cast:

B b;
A& aRef = B;
B& bRef = dynamic_cast<B&>(aRef);

dynamic_cast 使用 RTTI(运行-时间类型信息)来验证操作,如果转换无效将抛出 std::bad_cast 异常。这不同于 dynamic_casting 指针,在这种情况下,强制转换 returns nullptr 而不是抛出异常。

Class A 有 private/public 个成员。 Class B 派生自 Class A,并且可能添加了更多 private/public 个成员。

Class B "is a" Class A 的导数。然而 Class A "is not a" Class B 的导数。(即:你可以向下转换 A->B 但不能向上转换 B-A。)

原因是,虽然 B 是 A 的一种,但 A 不是 B 的一种,因此 B 的 methods/members 不会出现(即使源代码中的方法具有相同的名称,它也会由于名称被编译器遮盖,因此编译的方法不同。

B b = (B) a 将不起作用,因为没有定义转换(构造函数或转换运算符)。 B b = (B&) a 有效是因为它将 a 转换为对 B 的引用(由 static_cast 向下转换),然后调用 B 的复制构造函数。但是在这种情况下,a 不是一个B 的实际对象,所以这是未定义的行为。 请参阅 C++ 标准中的 [expr.static.cast]

If the object of type “cv1 B” is actually a subobject of an object of type D, the result refers to the enclosing object of type D. Otherwise, the behavior is undefined.

C++ 标准中的

和 [expr.cast] 或 http://en.cppreference.com/w/cpp/language/explicit_cast and http://en.cppreference.com/w/cpp/language/cast_operator