4

确切地说,为什么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) 不存在。

4

3 回答 3

3

因为从Ato的隐式转换B不存在,而且您也没有定义明确的转换。

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

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

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

一旦您尝试B访问A. 因为你的实际对象是A,不是B

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

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

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

于 2015-12-17T07:08:02.507 回答
1

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

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

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

于 2015-12-17T07:20:10.387 回答
-1

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

B类“是”A类的派生。但是A类“不是”B类的派生。(IE:您可以向下转换A-> B但不能向上转换BA。)

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

于 2015-12-17T07:09:38.000 回答