As in Private function member called outside of class, one can write the following code:
#include <iostream>
class A {
public:
virtual void f() { std::cout << "A::f()"; }
};
class B : public A {
private:
void f() override { std::cout << "B::f()"; }
};
void g(A &g) { g.f(); }
int main() {
A a;
g(a);
a.f();
B b;
g(b);
b.f(); // compilation failure
}
Of course, the compiler refuses to compile the last line, because the static analysis of the code reveals that B::f()
is defined but private.
What seriously troubles me is the relation with the conceptual generalization/specialization. It is generally considered that you must be able to manipulate an instance of a subtype at least the same way you manipulate an instance of the super type.
This is the basis of the Liskov's substitution principle. In the given example, that is respected when g()
is called either with an argument of type A
or one of type B
. But the last line is not accepted, and it seems that in such a case the substitution principle is violated in some way (consider a call-by-name as in a macro-definition #define h(x) (x.f())
).
Even if one may consider that the Liskov's principle is not violated (macros are not real part of the language, so ok), the fact that the last line gives a compile-time error, at least means that objects of type B
can't be manipulated as A
's can be. So that B
is not a specialization of A
even if the derivation is public
.
Thus in C++, using a public
derivation does not guarantee that you are effectively implementing a specialization. You need to consider more properties of the code to be sure that you have a ‘‘correct’’ specialization.
Am I wrong ? Is someone able to give me a justification for it ? I would like a good semantic argument, I mean at least something much more elaborate than Stroustrup's ones like ‘‘C++ tries not to constrains you, you are free to use it if you want and not if you don't want’’. I think that a language need to be founded on a reasonable model, not on a huge list of possible tricks.