views:

341

answers:

4

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.

+2  A: 

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.

Benoît
+1  A: 

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.)

UncleBens
A: 

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.

MSN
Nice. I was using this approach for a formatting facet but wasn't sure if this was legal. Thank you!
hlx236sk
This is quite contrary to the NVI: The base class' function is public+virtual, but in NVI it's private+virtual and the public function calling it is nonvirtual.
Johannes Schaub - litb
@litb, Ah, whups. Well, I fixed the text since I missed the base public virtual, derived private virtual.
MSN
It still doesn't address the actual question of the legality of changing access to members.
Georg Fritzsche
I thought that was apparent based on the articles I linked to.
MSN
+4  A: 

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.

Georg Fritzsche