Leo*_*Hat 23 c++ parameters inheritance
有时在修复现有代码库中的缺陷时,我可能(通常是出于懒惰)决定更改方法:
void
MyClass::foo(uint32_t aBar)
{
    // Do something with aBar...
}
至:
void
MyClass::foo(uint32_t aBar, bool aSomeCondition)
{
    if (aSomeCondition)
    {
        // Do something with aBar...
    }
}
在代码审查期间,一位同事提到了一种更好的方法是子类MyClass来提供这种专门的功能.
但是,我认为,只要aSomeCondition不违反其目的或凝聚力,MyClass就可以使用它.只有当代码被标志和if语句渗透时,继承才是更好的选择,否则我们可能会进入架构宇航员领域.
这里的转折点是什么?
注意:我刚看到这个相关的答案表明a enum可能是比a更好的选择bool,但我认为我的问题仍然适用于这种情况.
VGE*_*VGE 28
这种问题不仅有一种解决方案.
Boolean的语义非常低.如果你想在将来添加一个新的条件,你将不得不添加一个新的参数... 
经过四年的维护,你的方法可能有六个参数,如果这些参数都是布尔值,它是维护者的非常好的陷阱.
如果案件是独家的,Enum是一个不错的选择.枚举可以轻松迁移到位掩码或上下文对象.
位掩码:C++包含C语言,你可以使用一些简单的旧实践.有时无符号int上的一个掩码是一个不错的选择(但你放松了类型检查),你可以错误地传递一个错误的掩码.这是从布尔或枚举参数平滑移动到这种模式的便捷方式.可以通过一些努力将位掩码迁移到上下文对象.您可能必须实现某种按位算术,例如operator |,   operator &如果您必须保持构建时兼容性.
如果行为的分割很大并且此行为与实例的生命周期相关,那么继承有时是一个很好的选择.请注意,您还必须使用多态,如果大量使用此方法,这可能会降低方法的速度.
最后,继承会引起你所有工厂代码的变化......如果你有多种方法可以独家改变,你会怎么做?你会弄乱你的特定类的代码......事实上,我认为这通常不是一个很好的主意.
方法拆分:另一种解决方案是将方法拆分为多个私有方法并提供两个或多个公共方法.
上下文对象:可以通过添加上下文参数来绕过C++和C缺少命名参数.我经常使用这种模式,特别是当我必须在复杂框架的层次上传递许多数据时.
class Context{
public:
  // usually not a good idea to add public data member but to my opinion this is an exception
  bool setup:1; 
  bool foo:1;
  bool bar:1;
  ...
  Context() : setup(0), foo(0), bar(0) ... {}
};
...    
Context ctx;
ctx.setup = true; ...
MyObj.foo(ctx);
注意:这对于最小化访问(或使用)静态数据或查询单例对象,TLS也很有用...上下文对象可以包含更多与算法相关的缓存数据.......让你的想象力自由发挥......
反模式
我在这里添加了几种反模式(以防止签名的某些变化):*永远不要这样做*
小智 20
不幸的是,我不认为这个问题有一个明确的答案(这是我在自己的代码中经常遇到的问题).使用布尔值:
 foo( x, true );  
电话很难理解.
有一个枚举:
 foo( x, UseHigherAccuracy );
它很容易理解,但你最终会得到这样的代码:
 foo( x, something == someval ? UseHigherAccuracy : UseLowerAccuracy );
这几乎没有改进.并具有多种功能:
 if ( something == someval ) {
      AccurateFoo( x );
 }
 else {
      InaccurateFoo( x );
 }
你最终得到了更多的代码.但我想这是最容易阅读的,我会倾向于使用,但我仍然不完全喜欢它:-(
但是我绝对不会做的一件事是子类.继承应该是您可以达到的最后一个工具.
我使用的一般准则是:如果aSomeCondition以主要方式改变函数的性质,那么我考虑子类化。
与添加仅具有较小影响的标志相比,子类化是一项相对较大的工作。
一些例子:
当然,通过完全隐藏底层数据结构可能会更好地处理最后一个,但我在这里假设您希望能够选择众多数据结构之一,例如性能等原因。