C++ private and protected virtual method和Is 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;
};
如果我将SetStateBool
和SetStateInt
放在类定义的公共部分会有什么影响?
答案 0 :(得分:2)
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();
};
由于公共接口是非虚拟接口,因此所有派生类也会自动进行日志记录。相反,如果您将公共SetStateBool
和SetStateInt
,则无法对所有派生类强制执行日志记录。
因此,使用NVI习惯用法的建议不是语法要求,但它是一个在所有派生上强制执行基类语义(日志记录或缓存)的工具类。
答案 1 :(得分:0)
不,语言中没有任何内容阻止您创建实现函数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)......而这就是成语的概念。