I changed my C++ base class to be protected
inheritance and my dynamic_cast
(s) stopped working.
Why should changing the inheritance to protected
change the behavior of dynamic_cast
?
struct Base {
static Base *lookupDerived(); // Actually returns a Derived * object.
};
struct Derived : protected /* Switch this to public to get it working */ Base {
static void test() {
Base *base = lookupDerived();
if (dynamic_cast<Derived *>(base)) {
std::cout << "It worked (we must be using public inheritance)." << std::endl;
} else {
std::cout << "It failed (we must be using protected inheritance)." << std::endl;
}
};
You as an outside user cannot access the protected or private members of a class. The same applies to protected or private inheritance. The authors of a class don't want outside users to access protected/private parent classes any more than they want outside users to access protected/private members.
One reason: Suppose the parent class has a non-virtual destructor. Deleting from an instance derived class from a base class pointer would result in undefined behavior. Making the parent class protected/private means you can't do this (see footnote).
Another reason: Suppose the authors of the class in question don't want outside users to have access to the public members of the parent class. One could use public inheritance (is-a) and demote those public interfaces to protected or private, but this would violate the Liskov substitution principle. Protected or private inheritance is not an is-a relationship. Those public methods become protected or private with protected or private inheritance. There's no problem with Liskov substitution because protected/private inheritance is not is-a.
Footnote: There is an ugly way around this: Use C-style casts. Outside users can cast a
derived class pointer to a base class pointer, even if the base class is not accessible. To me, that's yet another reason to compile with -Wold-style-cast -Werror
.
When you change your inheritance to protected, the relationship between your two classes is hidden from the exterior of the object.
Private (or proctected) inheritance is semantically different from public inheritance.
It is not a "is-a" relationship but a "implemented in terms of" relationship. Meaning that you cant use a base class as a handle to a derived object.