Consider the following snippet:
struct Base
{
virtual ~Base() {}
virtual void Foo() const = 0; // Public
};
class Child : public Base
{
virtual void Foo() const {} // Private
};
int main()
{
Child child;
child.Foo(); // Won't work. Foo is private in this context.
static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context.
}
Is this legal C++? "This" being changing the virtual function's access mode in the derived class.
Yes, changing the access mode in derived classes is legal.
This is similar in form but different in intent to the Non-Virtual Interface idiom. Some rationale is given here:
The point is that virtual functions exist to allow customization; unless they also need to be invoked directly from within derived classes' code, there's no need to ever make them anything but private.
As to why you would actually make something public
in base but private
in derived without private
or protected
inheritance is beyond me.
This is legal C++, §11.6/1 says:
Access is checked at the call point
using the type of the expression used
to denote the object for which the
member function is called (B* in the
example above). The access of the
member function in the class in which
it was defined (D in the example
above) is in general not known.
As you noted, Child::Foo()
is thus still accessible via the base class, which is in most cases undesired:
Child* c = new Child;
Base* b = c;
c->Foo(); // doesn't work, Child::Foo() is private
b->Foo(); // works, calls Child::Foo()
Basically, the declaration you refer to in the expression dictates the access mode - but virtual functions undermine that as another function then the named one may actually be invoked.
It is perfectly legal C++. You are simply defining a new method in Child class.
Now does it do what you want it to do, that's an other question.
I believe the access mode is not part of the method signature, which means that calling Base's Foo virtual method does eventually call Child's Foo method.
So here's the conclusion : it is legal c++ and it works the way you'd expect.
I am not taking into consideration the line child.Foo();
which can't work because there is no doubt it is trying to access Child's private Foo() method.
It seems to compile and call the right method.
Remember that access specifiers are there to help a disciplined programmer, not to prevent all attempts to circumvent it at all costs.
In this particular case, Child has no business making the overridden virtual function private: isn't it supposed to implement the public interface of Base, so the "is-a" relationship holds? (If you didn't use public inheritance, which means "Child is a Base", your trick wouldn't work.)