Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does protected inheritance cause dynamic_cast to fail?

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;
   }
};
like image 282
WilliamKF Avatar asked Oct 07 '12 00:10

WilliamKF


People also ask

What happens when a protected member is inherited in private mode?

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.

Is protected member inheritable?

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.

What does dynamic cast of a reference return if it fails?

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.

What is the use of the dynamic_cast operator?

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 .


1 Answers

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.

like image 133
David Hammen Avatar answered Oct 05 '22 23:10

David Hammen