"Do other languages (C++ or C#) have different rules on this?"
Well, C++ has different rules: the static or dynamic member function binding process and the access privileges enforcements are orthogonal.
Giving a member function the private
access privilege modifier means that this function can only be called by its declaring class, not by others (not even the derived classes). When you declare a private
member function as virtual
, even pure virtual (virtual void foo() = 0;
), you allow the base class to benefit from specialization while still enforcing the access privileges.
When it comes to virtual
member functions, access privileges tells you what you are supposed to do:
private virtual
means that you are allowed to specialize the behavior but the invocation of the member function is made by the base class, surely in a controlled fashion
protected virtual
means that you should / must invoke the upper class version of the member function when overriding it
So, in C++, access privilege and virtualness are independent of each other. Determining whether the function is to be statically or dynamically bound is the last step in resolving a function call.
Finally, the Template Method design pattern should be preferred over public virtual
member functions.
Reference: Conversations: Virtually Yours
The article gives a practical use of a private virtual
member function.
ISO/IEC 14882-2003 §3.4.1
Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (clause 5).
ISO/IEC 14882-2003 §5.2.2
The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function isvirtualand is not specified using aqualified-idthen the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression [Note: the dynamic type is the type of the object pointed or referred to by the current value of the object expression.