E
edam
I wondered if anyone had any insight as to why the C++ spec. was
designed with the following behaviour. I've been thinking about it all
morning and neither myself nor my colleagues are able to come up with
a
reason.
If a class is derived from a protected base class, then dynamic_cast
will not allow you to cast from a pointer or reference to the base
class to the deriving class. Here's some code to demonstrate the
point:
struct B {
virtual ~B() {};
};
struct D : protected B {
};
void main() {
D d;
B &b = dynamic_cast< B & >( d ); // compiler error
B &b2 = ( B & )d; // circumventing protection
D &d2 = dynamic_cast< D & >( b2 ); // run-time error
}
The error my compiler (GCC 4.4.3) gave me was "error: ‘B’ is an
inaccessible base of ‘D’" and the run-time error was a thrown
std::bad_cast. Both of these seem reasonable, since main() should not
have access to D's protected base. So far so good. But now consider
this code:
struct B {
virtual ~B() {};
};
struct D : protected B {
void foo() {
B &b = dynamic_cast< B & >( *this ); // upcast ok here
D &d = dynamic_cast< D & >( b ); // runtime error
}
friend class F;
};
struct F {
void foo( D &dref ) {
B &b = dynamic_cast< B & >( dref ); // upcast ok here
D &d = dynamic_cast< D & >( b ); // runtime error
}
};
void main() {
D d;
d.foo();
F f;
f.foo( d );
}
Here, we successfully upcast from a derived class reference to a
protected base class reference in two places: from a member function
of
the derived class and from a member function of a friend class.
We also attempt to downcast from a protected base class reference to a
derived class reference in the same two places--an action that would
succeed if we weren't using protected inheritance. Both attempts fail
with std::bad_cast thrown.
It is my understanding that, where public inheritance represents the
"is-a" relationship, protected and private inheritance are another way
of expressing the "has-a" relationship in OOP; an alternative to using
member variables. In this sense, by using protected inheritance, you
are hiding the implementation details of the derived class from users
of that class. Those implementation details should only be available
to
methods of D and any classes that you derive from D, as is the case
with protected member functions and variables.
Given this, I cannot understand why a member function of the derived
class or of a friend class can not downcast a protected base class
reference to a derived class reference specifically because we are
using protected inheritance. Surely, if the intention of protected and
private inheritance is to protect and make private the implementation
of a class, you shouldn't be hiding that implementation from the class
its self and its friends!
Also, by way of comparison, consider an implementation where B is
a protected member variable of D, instead of as its protected base.
This would still represent the "has-a" relationship (D has a B). If
this were the case, both D's member functions and D's friends would
have access to its B member variable (its implementation). This seems
to further indicate that downcasting to a derived class from its
protected base should be allowed in member functions and friends of
the derived class.
I was wondering if anyone had any ideas as to why the design of C++
seems to prohibit it in all cases? I was also wondering if anyone
could
suggest a method of performing this downcast from a member/friend
without having to resort to reinterpret_cast?
Thanks,
Tim.
designed with the following behaviour. I've been thinking about it all
morning and neither myself nor my colleagues are able to come up with
a
reason.
If a class is derived from a protected base class, then dynamic_cast
will not allow you to cast from a pointer or reference to the base
class to the deriving class. Here's some code to demonstrate the
point:
struct B {
virtual ~B() {};
};
struct D : protected B {
};
void main() {
D d;
B &b = dynamic_cast< B & >( d ); // compiler error
B &b2 = ( B & )d; // circumventing protection
D &d2 = dynamic_cast< D & >( b2 ); // run-time error
}
The error my compiler (GCC 4.4.3) gave me was "error: ‘B’ is an
inaccessible base of ‘D’" and the run-time error was a thrown
std::bad_cast. Both of these seem reasonable, since main() should not
have access to D's protected base. So far so good. But now consider
this code:
struct B {
virtual ~B() {};
};
struct D : protected B {
void foo() {
B &b = dynamic_cast< B & >( *this ); // upcast ok here
D &d = dynamic_cast< D & >( b ); // runtime error
}
friend class F;
};
struct F {
void foo( D &dref ) {
B &b = dynamic_cast< B & >( dref ); // upcast ok here
D &d = dynamic_cast< D & >( b ); // runtime error
}
};
void main() {
D d;
d.foo();
F f;
f.foo( d );
}
Here, we successfully upcast from a derived class reference to a
protected base class reference in two places: from a member function
of
the derived class and from a member function of a friend class.
We also attempt to downcast from a protected base class reference to a
derived class reference in the same two places--an action that would
succeed if we weren't using protected inheritance. Both attempts fail
with std::bad_cast thrown.
It is my understanding that, where public inheritance represents the
"is-a" relationship, protected and private inheritance are another way
of expressing the "has-a" relationship in OOP; an alternative to using
member variables. In this sense, by using protected inheritance, you
are hiding the implementation details of the derived class from users
of that class. Those implementation details should only be available
to
methods of D and any classes that you derive from D, as is the case
with protected member functions and variables.
Given this, I cannot understand why a member function of the derived
class or of a friend class can not downcast a protected base class
reference to a derived class reference specifically because we are
using protected inheritance. Surely, if the intention of protected and
private inheritance is to protect and make private the implementation
of a class, you shouldn't be hiding that implementation from the class
its self and its friends!
Also, by way of comparison, consider an implementation where B is
a protected member variable of D, instead of as its protected base.
This would still represent the "has-a" relationship (D has a B). If
this were the case, both D's member functions and D's friends would
have access to its B member variable (its implementation). This seems
to further indicate that downcasting to a derived class from its
protected base should be allowed in member functions and friends of
the derived class.
I was wondering if anyone had any ideas as to why the design of C++
seems to prohibit it in all cases? I was also wondering if anyone
could
suggest a method of performing this downcast from a member/friend
without having to resort to reinterpret_cast?
Thanks,
Tim.