【发布时间】:2014-03-24 06:44:55
【问题描述】:
不使用公共虚拟方法有什么正当理由吗?
我在某处读到我们应该避免使用公共虚拟方法,但我想从专家那里确认这是否有效?
【问题讨论】:
-
由于派生可以简单地通过覆盖虚拟方法来篡改虚拟方法的访问限制,我真的很好奇该声明的作者在提出该声明时的想法。
-
有,那是你不需要它们的时候。
标签: c++ c++11 polymorphism
不使用公共虚拟方法有什么正当理由吗?
我在某处读到我们应该避免使用公共虚拟方法,但我想从专家那里确认这是否有效?
【问题讨论】:
标签: c++ c++11 polymorphism
对于良好且稳定的 API 设计,Non-Virtual-Interface 是一个很好的习惯用法。
我将遵循现有的优秀文献:
另请参阅这些精彩的答案:
(Sumant Tambe 在他的博客上有一个有趣的矩阵 Design Intent Implications,其中包含更多关于设计意图的信息。)
【讨论】:
将virtual 函数设为非公共允许基类围绕它们创建协议。如果不出意外,这可以用于一些只需要检测基类的会计/分析。基类公共接口可以是inline 函数,只是转发给virtual 函数。遗憾的是,派生类的限制可以放宽,即,派生类可以公开访问基类中的virtual 函数。
实际上还有另一个重要的原因使virtual 函数protected:重载virtual 函数时(例如,std::num_put<...> 中的do_put() 成员)很容易在仅覆盖一个时意外隐藏其他重载的功能。当virtual 函数既是自定义点又是调用接口时,这很容易导致令人惊讶的行为。当virtual函数为protected时,很明显调用接口和自定义接口实际上是不同的,即使直接使用派生类也可以避免问题。 virtual 函数可能希望成为 protected 以允许覆盖函数从基类调用默认实现。如果没有默认实现,virtual函数也可以是private。
这个答案讨论了为什么 virtual 函数不应该是 public。您是否应该首先拥有virtual 函数是一个单独的问题,答案有些不重要。
【讨论】:
我想到一件事——不使用公共虚拟方法简化了类接口与实现的分离。比如说,你提供了一个公共方法来做某事:
public:
virtual void DoSth()
{
}
一段时间后,引入了更改,这需要在做某事之前初始化和完成基类。如果您已经从您的类派生了一些类,则必须更改它们的实现。但是如果你是这样写的:
protected:
virtual void InternalDoSth()
{
}
public:
void DoSth()
{
InternalDoSth();
}
这只是改变 DoSth 的实现的问题:
public:
void DoSth()
{
InitializeSth();
InternalDoSth();
FinalizeSth();
}
创建两级虚函数非常便宜,并且为您提供了一个额外的层,这使您可以轻松控制将来调用虚方法的方式。
【讨论】: