在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
的隐式转换不存在,而且您也没有定义显式转换。
另一方面,引用强制转换是有效的,因为它允许用于继承的类型。更准确地说,可以在同一继承层次结构中的不同类之间双向强制转换。指针也是如此。如果你想为进一步的研究提供一些指导,相关的概念被称为多态性。
但是,请注意,只有是类型为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的方法/成员将不存在(即使一个方法在源代码中具有相同的名称,由于名称被编译器模糊,它也不会是编译的相同方法)。
- 强制转换为引用类型
- 如何将 int 引用安全地转换为长引用?
- 右值引用转换后的地址更改
- C++将引用转换为指针?
- 如果可能的话,C++总是更喜欢右值引用转换运算符而不是常量左值引用吗?
- 将常量引用转换为智能指针而不复制
- 为什么不能将继承自(非模板)类 B 的实例化类模板 A 的引用转换为对 B 的引用?
- 通过 see 命令引用转换运算符
- 将项目转换为 qt5 并将未定义的引用转换为 'vtable for qt5 和 cmake
- 从 r 值引用转换为 l 值引用,为什么有效
- C++从右值引用转换为右值引用 a unique_ptr
- 将引用转换为 C++ 中的指针表示形式
- 如何正确地将引用转换为指针
- 正在将常量结构引用转换为非常量指针
- 将传递引用转换为传递返回
- 将.net引用转换为c++引用
- c++向量引用转换
- 如何将对int8_t的引用转换为对uint8_t的引用
- 如何在c++中将数字字符引用转换为Unicode
- 是否可以将对 std::list<int*> 的引用转换为对 std::list<const int*> 的引用?