在NVI成语下,为什么虚拟功能不能公开?
Under the NVI idiom, why can't the virtual function be public?
c++私有和受保护的虚方法和不使用公共虚方法是否有任何正当理由?讨论了非虚接口(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
在类定义的公共部分有什么影响?
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习惯用法并不是一个语法要求,而是一个在所有派生类上强制基类语义(日志记录或缓存)的工具。
不,语言中没有任何东西可以阻止您创建public
实现函数。原则上,您可以这样做:
class Base {
public:
virtual ~Base(){}
void work() { do_work(); }
virtual void do_work() = 0;
};
,其中实现是公共的。Meyers说有时候你必须这样做,他可能是在说开发人员有时会被限制在一个设计糟糕的环境中开发。
例如,您可以违背RAII习惯用法,这样做:
std::unique_ptr<MyClass,DoNothingDeleter> ptr ( new MyClass(...) );
中析构函数实际上不会释放内存(是的,我以前不得不处理这种类型的场景)。语言并没有明令禁止,但这通常是个坏主意。换句话说,仅仅因为它是合法的,并不意味着它是道德的。这就是习语的概念。
- 为什么我不能拥有某些私有会员功能?
- 为什么这个base64解码/编码功能不能正常工作?
- C++ - 多态性:不能使用功能
- 为什么在传递lambda而不是功能指针时不能推断模板参数
- MPI_Op_create:候选功能不可行.自定义结构指针不能解释为空指针
- 制作uint128库却不能,找出什么功能搞砸了
- opencv2 可以使用 cmake 构建,但不能使用 CLion "build" 功能?
- 我不能在函数中使用新功能C++构建
- 不能在QtCreator中使用使用g++ 7.2的c ++ 17功能
- 为什么不能将std :: stol转换为std ::功能对象
- 为什么这两个功能不能超载
- 为什么不能从指针施放到模板功能中的指针
- 我正在使用Xcode进行c ++编程和学习。为什么我不能在一个项目中放置许多具有 MAIN 功能的单独源文件?
- 我不能在不使用指针的情况下返回 2d 数组!我正在制作一个井字游戏类型游戏,这是我的向上移动功能
- 虚拟功能不能是朋友
- 你能不能使用 JNI 在从 java 调用的 c++ 函数中创建一个新的 JVM
- "官方"CUDA 减少功能不能接受某些数字?
- 我能不能做一个unique_ptr不拥有其尖头对象的所有权
- 问题.所有功能都可以在发布文件夹中工作,但不能在程序文件中工作
- 能不能回式混?或者变通的解决方案