在C ++中何时非法上传?

我非常肯定我理解了向上转换和向下转换之间的一般区别,尤其是在C ++中。 我明白,我们不能总是downcast,因为将基类指针投射到派生类指针会假定指向的基类对象具有派生类的所有成员。

在这个学期的初期,我的教授告诉全class学生,在C ++中有时候也是非法的,但是我似乎错过了在笔记里为什么不记得什么时候发生的事情。

任何人都可以告诉我什么时候在C ++中使用upcast是非法的?

如果“非法”是指不合法的话,那么如果基类是不可访问或模棱两可的,则是非法的。

  • 例如,当基类是私有的时候是不可访问的。

    class A {}; class B : A {}; ... B b; A *pa = &b; // ERROR: base class is inaccessible 

    请注意,即使在C ++ 11中,C风格转换也可以“突破”访问保护,并执行正式的正确上传

     A *pa = (A *) &b; // OK, not a `reinterpret_cast`, but a valid upcast 

    这个用法当然应该避免。

  • 如果源types包含多个目标types的基本子对象(通过多重inheritance),则不明确。

     class A {}; class B : public A {}; class C : public A {}; class D : public B, public C {}; D d; A *pa = &d; // ERROR: base class is ambiguous 

    在这种情况下,可以通过用中间上行明确地“行走”所希望的上行path到达基地不再模棱两可的点来执行上行

     B* pb = &d; A* pa = pb; // OK: points to 'D::B::A' subobject 

如果基类是不明确的(通过不同的pathinheritance两次或更多),那么你不能在一个单独的步骤中进行上传。

如果基类是不可访问的,那么唯一的方法就是使用C风格转换。 这是一个特殊的情况,这是唯一可以做这个工作的人。 从本质上讲,它的行为就像一个不受可访问性限制的static_cast


Standardese。

C ++ 11§5.4/ 4:

…在[C cast]中,在下列情况下执行static_cast ,即使基类不可访问,转换也是有效的:

  • 可以将指向派生类types的对象的指针或派生类types的左值或右值分别显式地转换为指针或对明确的基类types的引用;
  • 可以将指向派生类types的成员的指针显式地转换为指向非明确的非虚拟基类types的成员的指针;
  • 指向明确的非虚拟基类types的对象的指针,明确的非虚拟基类types的glvalue或指向明确的非虚拟基类types的成员的指针可被显式地转换为指针,引用或指向派生类types成员的指针。

歧义的例子:

 struct Base {}; struct M1: Base {}; struct M2: Base {}; struct Derived: M1, M2 {}; auto main() -> int { Derived d; //static_cast<Base&>( d ); //! Ambiguous static_cast<Base&>( static_cast<M2&>( d ) ); // OK } 

无法访问的基地示例,在(通常)地址调整中:

 struct Base { int value; Base( int x ): value( x ) {} }; class Derived : private Base { public: virtual ~Derived() {} // Just to involve an address adjustment. Derived(): Base( 42 ) {} }; #include <iostream> using namespace std; auto main() -> int { Derived d; Base& b = (Base&) d; cout << "Derived at " << &d << ", base at " << &b << endl; cout << b.value << endl; }; 

在C ++中有两种情况是不合理的(在编译时被诊断出来):

  1. 有问题的基类不可访问

     class base {}; class derived : base {}; int main() { derived x; base& y = x; // invalid because not accessible. // Solution: C-style cast (as static_cast without access-check) base& y1 = (base&)x; } 
  2. 所讨论的基类子对象并不是明确的

     class base {}; struct A1 : base {}; struct A2 : base {}; struct derived : A1, A2 {}; int main() { derived x; base& y = x; // invalid because ambiguous. // Solution 1, scope resolution: base& y1 = static_cast<A1::base&>(x); base& y2 = static_cast<A2::base&>(x); // Solution 2, intermediate unambiguous steps: A1& a1 = x; A2& a2 = x; base& ya1 = a1; base& ya2 = a2; }