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;
}
};
With private inheritance, public and protected member of the base class become private members of the derived class. That means the methods of the base class do not become the public interface of the derived object. However, they can be used inside the member functions of the derived class.
protected inheritance makes the public and protected members of the base class protected in the derived class. private inheritance makes the public and protected members of the base class private in the derived class.
A failing dynamic cast to a reference type throws a bad_cast exception. A dynamic cast with a reference is a good way to test for a coding assumption.
The primary purpose for the dynamic_cast operator is to perform type-safe downcasts. A downcast is the conversion of a pointer or reference to a class A to pointer or reference to a class B , where class A is a base class of B .
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With