According to the NVI idiom, why can't a virtual feature be publicly available?

C ++ private and secure virtual method and Is there a good reason not to use public virtual methods? talk about non-virtual interface ( NVI ) and non-public virtual functions and their symbiosis. Scott Meyers also says in Effective C ++ that

Sometimes a virtual function even needs to be publicly available, but then the NVI idiom cannot be applied.

What I have not seen is why the NVI requires implementation-specific virtual functions to be non-public? From Herb Sutter's article "Virtuality", it is said that it is good practice, for example, to separate the public (client) interface from the implementation details (non-public interface) well. I want to know if there is any language function that I missed that semantically prevents the use of NVI if such virtual functions are declared public?

For instance:

class Engine { public: void SetState( int var, bool val ); { SetStateBool( int var, bool val ); } void SetState( int var, int val ); { SetStateInt( int var, int val ); } private: virtual void SetStateBool(int var, bool val ) = 0; virtual void SetStateInt(int var, int val ) = 0; }; 

What are the effects if I put SetStateBool and SetStateInt in the public section of the class definition?

+5
source share
2 answers

TL; DR : you can, but you shouldn't.

Suppose you want each call to the public interface to be correctly registered (legal requirement for financial services, for example.)

 class Engine { public: void SetState( int var, bool val ); { logToFile(); SetStateBool( int var, bool val ); } void SetState( int var, int val ); { logToFile(); SetStateInt( int var, int val ); } private: virtual void SetStateBool(int var, bool val ) = 0; virtual void SetStateInt(int var, int val ) = 0; void logToFile(); }; 

Since the open interface is not virtual, all derived classes are also automatically registered. If you would SetStateBool make SetStateBool and SetStateInt public, you would not be able to force logging for all derived classes.

Therefore, the recommendation to use the NVI idiom is not a syntactic requirement, but is a tool to provide semantics for the base class (logging or caching) on ​​all derived classes.

+2
source

No, there is nothing in this language that would prevent you from implementing the public implementation function. You could basically do something like:

 class Base { public: virtual ~Base(){} void work() { do_work(); } virtual void do_work() = 0; }; 

where the implementation is publicly available. Meyers says that sometimes you have to do this, he probably states that a developer can sometimes be limited to developing in a poorly designed context.

For example, you can go against the RAII idiom and do something like this:

 std::unique_ptr<MyClass,DoNothingDeleter> ptr ( new MyClass(...) ); 

where the destructor will not actually free the memory (and yes, I had to deal with this type of script before). Language does not prohibit this, but it is usually a bad idea. In other words, just because it is legal does not mean that it is moral (credit to Marshall Kline) ... and that the concept of idiom.

0
source

All Articles