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

C++ 在C++;,为什么转换到派生类型的引用有效?,c++,inheritance,casting,reference,derived-instances,C++,Inheritance,Casting,Reference,Derived Instances,确切地说,为什么bb=(B&)a编译并工作,而bb=(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&)

确切地说,为什么
bb=(B&)a
编译并工作,而
bb=(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;
}
#包括
使用名称空间std;

类A{public:void f(){cout,因为从
A
B
的隐式转换不存在,而且您也没有定义显式转换

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

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

B b;
A& aRef = B; // equivalent of A& ref = (A&)B;
B& bRef = (B&)aRef;
当您尝试访问
A
中不存在的
B
的某些数据或方法时,您所做的操作将在运行时失败。因为您的实际对象是
A
,而不是
B

向上转换(从后代向上转换)总是安全的,因为继承基类的类的任何对象都是有效的基类对象。但是,向下转换是危险的,因为我上面解释了确切的原因,决不能使用C样式转换。相反,请使用
动态转换

B b;
A& aRef = B;
B& bRef = dynamic_cast<B&>(aRef);
B;
A&aRef=B;
B&bRef=动态铸造(aRef);

dynamic\u cast
使用RTTI(运行时类型信息)验证操作,并在转换无效时引发
std::bad_cast
异常。这与
动态_cast
ing指针不同,在这种情况下,强制转换返回
nullptr
,而不是引发异常。

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

“B类”是“a类”的衍生产品,但“a类”不是“B类”的衍生产品。(即:可以向下投射a->B,但不能向上投射B-a。)

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

B=(B)a
不会工作,因为没有转换(构造函数或转换运算符)定义了。
bb=(B&)a
之所以有效,是因为它将
a
转换为对B的引用(由a
static\u cast向下转换),然后调用B的复制构造函数。但是在这种情况下,
a
不是
B
的实际对象,因此这是未定义的行为。 见[ Exp.static .Case]在C++标准

如果类型为“cv1 B”的对象实际上是类型为D的对象的子对象,则结果引用封闭对象 类型为D的对象。否则,行为未定义


《C++标准》和

< P>和[ExPR.Cas]:“为什么?”?您是否需要引用标准中指定此行为的内容?或者需要一个深刻的哲学原因来解释为什么允许这样做是一个坏主意?显然是第一个原因。我不知道为什么标准允许转换为派生类型引用,但不允许转换为派生类型实例。如果按照标准将引用解释为p,这是有意义的ointers。当你需要的只是
'\n'
时,不要使用
std::endl
。这似乎不能回答问题。同意。此外,尽管我理解你的意思,但没有人会问这个问题。这一措辞令人困惑;C样式转换正在执行
重新解释转换
,因为它允许任何左值转换为into任何类型的引用。听起来好像您在暗示C样式强制转换正在[expr.cast]部分执行
静态强制转换
。并且,C样式强制转换将按以下顺序执行
常量强制转换
静态强制转换
静态强制转换
(带扩展名)接下来是
const\u cast
reinterpret\u cast
reinterpret\u cast
,然后是
const\u cast
@CollinDauphinee在这种情况下,它应该执行
静态\u cast
。我在函数调用中确保只有派生类型的实例被传递给以基类型为基础的函数因此,你会说,类型转换是引用类型的引用,因为在场景后面,C++将引用解释为指针,因为我知道这里使用指针代替引用是有效的。我只是不确定这是一个C++标准规范。pret引用为指针。“仅将派生类型的实例传递给以基类型为参数的函数”。那么,如果它总是获取派生类型,为什么它要将基类型作为参数呢?向编译器隐藏类型有什么意义?标准并没有说幕后引用是指针,但每个编译器都是这样实现的them@Raymond232:引用与指针非常相似,但更安全一点(例如,与指针不同,引用不能取消初始化)@Raymond232在@n.m.提出的问题旁边。你的
g
函数以
A
为参数,在这里进行对象切片,因此,无论你传递给函数调用的是哪种类型,当它转到这个函数时,它都会复制到
A
对象,因此,这个代码的行为总是未定义的。