If the base class is ambiguous (inherited two or more times via different paths) then you can’t do an upcast in a single step.
If the base class is inaccessible then the only way to upcast is to use a C style cast. This is a special case of that cast, it's the only one that can do the job. Essentially it then behaves as a static_cast
that's not limited by accessibility.
Standardese.
C++11 §5.4/4:
” … in [a C cast] performing a static_cast
in the following situations the conversion
is valid even if the base class is inaccessible:
- a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicitly
converted to a pointer or reference to an unambiguous base class type, respectively;
- a pointer to member of derived class type may be explicitly converted to a pointer to member of an
unambiguous non-virtual base class type;
- a pointer to an object of an unambiguous non-virtual base class type, a glvalue of an unambiguous
non-virtual base class type, or a pointer to member of an unambiguous non-virtual base class type may be explicitly converted to a pointer, a reference, or a pointer to member of a derived class type,
respectively.
Example of ambiguity:
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
}
Example of inaccessible base, with (usually) address adjustment in the cast:
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;
};