6

Why is the call to f not resolving to the first function overload? I get the error:

source.cpp: In function 'int main()':
source.cpp:12:31: error: 'A' is an inaccessible base of 'B'

class A {}; class B : A {};

void f(const A &)  { std::cout << "const A &"; }
template <typename T> void f(T) { std::cout << "Generic";  }

int main() {

   B b;

   f(dynamic_cast<const A &>(b));

}

Note that if I take out the dynamic_cast the code will work yet the second f is called (it prints "Generic"). But what I'm trying to do is to get the first call. I figured a dynamic_cast would work, but for some reason it causes problems. What am I doing wrong here?

template boy
  • 10,230
  • 8
  • 61
  • 97

4 Answers4

10

The default class inheritance is private (class B : A {}; defaults to class B : private A {};).

So you can't handle b through type A.

EDIT: Like Rob said :), the way to fix it is by using public inheritance:

class B : public A {};

EDIT:
The relationship between a publicly derived class and its base class is "is a", meaning that it is a specialization of a more generic type, and as such, it implements the behavior of that generic class and possibly more.

The relationship between a privately derived class and its base class is "implemented in terms of". It prevents objects from being considered extensions of the base class. A good example of its use is boost::noncopyable that prevents objects of a privately derived class from being copied. http://www.boost.org/doc/libs/1_52_0/libs/utility/utility.htm#Class_noncopyable

In the hypothetical case that the requirements include private inheritance and at some point a function is created that wants to reference the object as its base, a public method returning a casted to base class pointer this will do it much like a traditional get() accesses a private data member maintaining the original purpose.

public:
    A *getBase() { return static_cast<A *>(this); }

And then accessed like this:

f(b.getBase());
imreal
  • 10,178
  • 2
  • 32
  • 48
  • 2
    And the solution is `class B : public A {};` – Robᵩ Dec 13 '12 at 23:02
  • Strictly speaking, to say that public inheritance is a "way to fix it" is rather misleading. To fix *what* exactly? Public inheritance is no more than a way to make the compiler stop complaining. Whether it makes sense in the OP's code depends on the OP's intent. It might actually make no sense at all. – AnT stands with Russia Dec 13 '12 at 23:06
  • 1
    @AndreyT "But what I'm trying to do is to get the first call." The OP forgot or didn't know to put `public`, that seems clear. – John Kugelman Dec 13 '12 at 23:11
  • @JohnKugelman - but it's a valid point. If the private inheritance was a deliberate design decision, **and** it's appropriate to call the first version of `f`, then the solution must be something other than changing the inheritance. Granted, that's a lot of if's, and probably not the case here. – Pete Becker Dec 13 '12 at 23:13
  • @John Kugelman: Both the code and the objective "to get the first call" are too abstract to be interpreted in any specific way. Arguing about the proper way to "fix" it is like arguing about what's wrong in `2 + 2 = 5`: some will way that it should be `2 + 2 = 4`, the other will argue that it is supposed to be `2 + 3 = 5`. – AnT stands with Russia Dec 13 '12 at 23:22
4

A is a private base of B, so there are very few places where an object of type B can be treated as an A&. If you change the inheritance to public the cast will work, and select the non-template version of f. But dynamic_cast is overkill; every object of type B is an object of type A, so you can use static_cast to disambiguate the call.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • So for what kind of situation would I use `dynamic_cast` in (with classes)?? – template boy Dec 13 '12 at 23:06
  • To go the other way, from an `A&` to a `B&`; that would be a checked conversion, and you'd get an exception if the referenced object wasn't a `B`. For that to work, though, `A` must have at least one virtual function. – Pete Becker Dec 13 '12 at 23:09
2

There's nothing special about dynamic_cast when it comes to upcasts. dynamic_cast is equivalent to static_cast in such cases. It is performed at compile-time if the base exists, is unambiguous and is accessible. It fails to compile otherwise.

This is exactly what happens in your case. The base is inaccessible (as the compiler told you already) so the cast fails to compile.

Without the cast the first function is excluded from the overload resolution candidate list (since the base is inaccessible), and the second one wins.

In fact, you don't really need any cast to perform legal upcasts in overwhelming majority of cases. As for illegal upcasts, no C++ cast will help you with that (the only cast that can "break through" private inheritance is C-style cast.)

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

It will fail because of the private inheritance, as mentioned, and because b is passed as an object. dynamic_cast will only work for pointers and references.

See: http://www.cplusplus.com/doc/tutorial/typecasting/

JGaarsdal
  • 241
  • 1
  • 6