As already explained very well by others, this works exactly as by the C++ rules. The key design assumption of the C++ language is that the programmer knows what he's doing:
C makes it easy to shoot yourself in the foot; C++ makes it harder,
but when you do it blows your whole leg off.
- Bjarne Stroustrup
Here, your design is flawed ! You want B to inherit from A (so B is an A), but at the same time, you want that it can't be used like an A (so B is not really an A after all):
class A {
public:
virtual void greet() { cout <<"Hello, I'm "<<this<<endl;}
virtual void tell() { cout<<"I talk !"<<endl; }
};
class B : public A {
private:
void greet() override { cout <<"Hello, I can tell you privatly that I'm "<<this<<" incognito"<<endl;}
};
Humans can be confused by such paradoxical injunction. The C++ compiler thinks you must have good reasons to do so and plays by the book:
A a;
a.greet(); // ok
B b;
b.greet(); // error: you said it was not accessible
A& b_as_a = b;
b_as_a.greet(); // ok: you said that A's interface had to be used
If you want A's public functions to be inaccessible, you should tell the compiler by using non public inheritance:
class C : protected A {
private:
void greet() override { cout <<"Hello, I can't tell you anything, but I'm "<<this<<endl;}
};
This means that a C is implemented based on an A, but that the outside world shouldn't knwow it. This is much cleaner:
C c;
c.greet(); // error, as for B
A& c_as_a = c; // ouch: no workaround: because the A inheritance is procteted
Typically, you'd use this kind of inheritance if you want to reuse A's features to build a C class with a completely different interface. Yes, C++ can enforce tighter rules if you ask :-).
Typically, you would exposed completely different functions. But what if you'd want to use one of A's public function for convenience, it's easy:
class C : protected A {
private:
void greet() override { cout <<"Hello, I can't tell you anything, but I'm "<<this<<endl;}
public:
using A::tell; // reuse and expose as it is
};