Rich
Rich

Reputation: 1851

Under the NVI idiom, why can't the virtual function be public?

C++ private and protected virtual method and Is there any valid reason for not using public virtual methods? are talking about Non-Virtual Interface (NVI) and non-public virtual function and their symbiosis. Scott Meyers also says in Effective C++ that

Sometimes a virtual function even has to be public, but then the NVI idiom can't really be applied.

What I failed to see is why NVI requires that the implementation specific virtual function(s) be non-public? From Herb Sutter's article Virtuality, it is saying that it is a good practice to follow, e.g., it is good to separate public (client) interface from the implementation details (the non-public interface). What I want to know is if there is any language feature I missed that semantically prevents NVI being applied if such virtual functions are declared public?

For example:

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 public section of the class definition?

Upvotes: 8

Views: 2898

Answers (2)

Kyle Knoepfel
Kyle Knoepfel

Reputation: 1698

No, there is nothing in the language that prevents you from making an implementation function public. You could, in principle, do something like:

class Base {
public:

   virtual ~Base(){}

   void work() { do_work(); }
   virtual void do_work() = 0;

};

where the implementation is public. By Meyers saying that sometimes you have to do that, he's probably stating that the developer can be constrained at times to develop within a poorly designed context.

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

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

where the destructor actually will not free the memory (and yes, I've had to deal with this type of scenario before). The language does not forbid it, but it is generally a bad idea. In other words, just because it's legal, does not mean it is moral (credit Marshall Cline)...and that's the concept of the idiom.

Upvotes: 0

TemplateRex
TemplateRex

Reputation: 70516

TLDR: You can, but you shouldn't.

Suppose you want to make sure that every call to the public interface is properly logged (financial services legal requirement e.g.)

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();    
};

Because the public interface is non-virtual, all derived classes automatically have logging as well. If instead you would have made SetStateBool and SetStateInt public, you could not have enforced logging for all derived classes.

So the recommendation to use the NVI idiom is not a syntactic requirement, but it's a tool to enforce the base class semantics (logging, or caching) on all derived classes.

Upvotes: 11

Related Questions