在 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) 不存在。
因为从A
到B
的隐式转换不存在,而且你也没有定义显式。
另一方面,引用转换是有效的,因为它允许用于继承类型。更准确地说,您可以在同一继承层次结构中的不同 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_cast
ing 指针,在这种情况下,强制转换 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
确切地说,为什么在下面的程序中 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) 不存在。
因为从A
到B
的隐式转换不存在,而且你也没有定义显式。
另一方面,引用转换是有效的,因为它允许用于继承类型。更准确地说,您可以在同一继承层次结构中的不同 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_cast
ing 指针,在这种情况下,强制转换 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]
C++ 标准中的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.
和 [expr.cast] 或 http://en.cppreference.com/w/cpp/language/explicit_cast and http://en.cppreference.com/w/cpp/language/cast_operator