在C++中,为什么对派生类型的引用进行强制转换

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

本文关键字:引用 转换 类型 C++ 为什么 派生      更新时间:2023-10-16

确切地说,为什么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的隐式转换不存在,而且您也没有定义显式转换。

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

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

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

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

向上转换(从子代到上级)总是安全的,因为类中继承基类的任何对象都是有效的基对象。然而,由于我上面解释的确切原因,下转换是危险的,并且永远不应该使用C样式的转换。相反,使用dynamic_cast:

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

dynamic_cast使用RTTI(运行时类型信息)来验证操作,如果转换无效,则会引发std::bad_cast异常。这与dynamic_cast ing指针不同,在这种情况下,强制转换返回nullptr,而不是抛出异常。

B b = (B) a无法工作,因为未定义转换(构造函数或转换运算符)。B b = (B&) a之所以有效,是因为它将a强制转换为对B的引用(通过static_cast进行下转换),然后调用B的复制构造函数。然而,在这种情况下,a不是B的实际对象,因此这是未定义的行为。参见C++标准中的[expr.static.cast]

如果类型为"cv1B"的对象实际上是类型为D的对象的子对象,则结果指的是封闭对象。否则,行为是未定义的。

和C++标准中的[expr.cast],或http://en.cppreference.com/w/cpp/language/explicit_cast和http://en.cppreference.com/w/cpp/language/cast_operator

类A具有私有/公共成员。类B派生自类A,并且可能添加了更多的私有/公共成员。

"B类"是"a类的衍生物"。然而,"a类"不是"B类的衍生物。(即:你可以向下广播a->B,但不能向上广播B-a。)

原因是,虽然B是a的一种,但a不是B的一种。因此,B的方法/成员将不存在(即使一个方法在源代码中具有相同的名称,由于名称被编译器模糊,它也不会是编译的相同方法)。