首页 文章

根据NVI惯用法,为什么虚拟功能不能公开?

提问于
浏览
6

C++ private and protected virtual methodIs there any valid reason for not using public virtual methods?正在讨论非虚拟接口( NVI )和非公共虚拟功能及其共生关系 . Scott Meyers也在Effective C中说过

有时虚拟功能甚至必须是公开的,但是NVI惯用法无法真正应用 .

我没有看到为什么NVI要求特定于实现的虚拟功能是非公开的?从Herb Sutter的文章Virtuality开始,它是一个很好的做法,例如,将公共(客户端)接口与实现细节(非公共接口)分开是好的 . 我想知道的是,如果有任何语言功能我错过了语义上会阻止NVI被应用,如果这些虚拟功能被公开?

例如:

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

如果我将 SetStateBoolSetStateInt 放在类定义的公共部分中有什么影响?

2 回答

  • 0

    TLDR :你可以,但你不应该 .

    假设您要确保正确记录对公共接口的每次调用(例如,金融服务法律要求)

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

    由于公共接口是非虚拟接口,因此所有派生类也会自动进行日志记录 . 如果您将 SetStateBoolSetStateInt 公开,则无法对所有派生类强制执行日志记录 .

    因此,使用NVI习语的建议不是语法要求,而是一种在所有派生类上强制执行基类语义(日志记录或缓存)的工具 .

  • 2

    不,语言中没有任何内容阻止您创建实现函数 public . 原则上,您可以执行以下操作:

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

    实施是公开的 . 梅耶斯说,有时你必须这样做,他可能会说开发人员有时会受限于在设计不佳的环境中发展 .

    例如,你可以反对RAII习语并做这样的事情:

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

    析构函数实际上不会释放内存(是的,我之前必须处理这种类型的场景) . 该语言并不禁止它,但通常是一个坏主意 . 换句话说,仅仅因为它是合法的,并不意味着它是道德的(信用Marshall Cline)......而这就是成语的概念 .

相关问题