c++ - 在 C++ 层次结构中放置 util 方法的位置
问题描述
我有一个基类作为接口和多个派生类。我有 2 个 util 函数,每个派生类方法都需要使用它们。所以我不能将 util 函数放在派生类中,因为它会重复代码。所以一种选择是我可以将它们放入单独的 util 命名空间中,但我不希望它暴露给客户端。所以这些方法需要隐藏在某个地方。我的设计应该是什么,或者我应该如何使用这些功能?
解决方案
有些人希望接口基类是空的纯虚拟抽象类,这对他们来说可能感觉像是“适当的设计”,但是这种抽象级别会导致实现本身的效率更低。但是,如果您真的想保持您的接口类完全抽象,只需在其之上添加另一层,然后所有实现都从该层派生:
Abstract pure virtual interface base class
^
|
|
Implementation base class: common things, including your utility functions
^ ^ ^
| | |
| | |
Impl1 Impl2 Impl3
-------- ...in code: --------
class IThing
{
public:
virtual void runAround();
virtual void makeAMess();
};
class ThingBase : public IThing
{
public:
// runAround() is not implemented here; implement it in derived classes
virtual void makeAMess()
{
// ...default implementation of makeAMess(), which a derived class
// can override if necessary...
}
private:
int utilFunc1(int a) { return ...whatever...; } // not virtual! (or, it could be, if necessary)
int utilFunc2(int a) { return ...whatever...; } // not virtual! (or, it could be, if necessary)
}
class Thing1 : public ThingBase
{
public:
virtual void runAround() { /* ...special code for Thing1... */ }
// Thing1 uses the default implementation of makeAMess()
}
class Thing2 : public ThingBase
{
public:
virtual void runAround() { /* ...special code for Thing2... */ }
// Thing2 uses the default implementation of makeAMess()
}
class Thing3 : public ThingBase
{
public:
virtual void runAround() { /* ...special code for Thing3... */ }
virtual void makeAMess() { /* ...special code for Thing3... */ }
}
如果所有实现之间有任何共同的数据或功能,请务必将其移至上面的实现基类。将其保留在每个派生实现之外。但是,如果该功能(方法)是接口方法的实现,那么为了调用它,您将不必要地为所有用户增加多态方法调用的(小)开销:
每个派生的 vtable 都会有一个用于该公共函数的额外函数指针,当从接口指针/引用调用时必须以多态方式调用该函数,即使该方法只有一个实现。每次这样的调用都需要额外的两三个指令,以及额外的内存提取,因为它是多态的。额外的开销通常不会被认为太多,但它是额外的开销,在某些情况下它可能很重要(例如operator[]()
,当在紧密循环中使用数千次时,“Array”类的多态:如果所有派生将有一个private
指向其数据分配位置的指针,然后您可以将该指针放在基类中并实现单个非多态版本operator[]()
基于该指针访问适当的元素)。
如果由于您的类型的性质,某些功能(及其相关数据)在它的所有派生中总是通用的,那么开销较低的事情是放弃使您的接口类完全抽象的理想,并移动它将通用功能(及其相关数据)放入接口类(现在不是完全抽象的),并且不要将方法virtual
. 我知道这会刺激一些人的神经,但实际上,如果不需要,为什么要支付多态性的成本呢?如果事实证明某些派生确实需要不同的功能,您可以随时对其进行重构。
Not-fully-abstract "interface" base class
^ ^ ^
| | |
| | |
Impl1 Impl2 Impl3
请注意,如果您这样做,您仍然可以在那些非多态方法中具有特定于派生的行为,因为非多态方法可以在必要时调用其他多态类方法。
推荐阅读
- ios - PerformSegueWithIdentifier 爆炸
- powershell - [System.Drawing.Text.PrivateFontCollection],OTF 字体,Windows 7/PS2.0
- c++ - 如何在 Visual Studio 2017 中构建 ISO C++03?
- r - 带引导程序的 Shiny 中并排图的动态数量
- php - 服务器中的电子邮件发送问题(Laravel 5.6)
- python - 熊猫重采样不会改变时间增量
- android - 如何为 Widget.MaterialComponents.Button 添加边距?
- node.js - Cloudfront 不使用 lambda 函数
- c++ - C ++ 17调用没有尖括号的模板类的静态方法
- google-cloud-platform - 有没有办法修改谷歌云任务设置?