C++ 对于重复的代码,哪一个是最好的?

C++ 对于重复的代码,哪一个是最好的?,c++,C++,我有一个类,它有两个成员函数,它们共享一段代码: void A::First() { firstFunctionEpilogue(); sharedPart(); } void A::Second() { secondFunctionEpilogue(); sharedPart(); } 当前,firstFunctionEpilogue()、secondFunctionEpilogue()和sharedPart()都不是函数调用,只是代码片段,sharedPart()

我有一个类,它有两个成员函数,它们共享一段代码:

void A::First()
{
   firstFunctionEpilogue();
   sharedPart();
}

void A::Second()
{
   secondFunctionEpilogue();
   sharedPart();
}
当前,
firstFunctionEpilogue()
secondFunctionEpilogue()
sharedPart()
都不是函数调用,只是代码片段,
sharedPart()
代码被复制。我想消除重复

共享代码不需要访问类的任何成员。因此,我可以将其作为以下三项之一实施:

  • 一个静态成员函数
  • 常量非静态成员函数或
  • 局部函数

哪种变体更好?为什么?

如果您的函数访问状态但不更改状态,则使用常量成员函数

您的案例:

如果您的函数1)不需要访问代码的任何成员,2)与该类相关,则将其作为类的静态函数

这样很明显,它既不是在修改状态,也不是基于对象的状态

您没有提及的额外案例:


还有一件事你也可以做。这就是让SharedPart接受一个成员函数指针,调用它,然后处理它的主体。如果你有很多第一个(),第二个(),第三个(),第四个()。。。这样的函数可以减少代码重复。这样,您就不需要一直调用SharedPart();在每个成员函数的末尾,您可以重用First()、Second()、THird()、。。。不调用代码的SharedPart()

或者它可能在另一个类中

或者,如果它是一个成员,它可以是虚拟的

有很多决定,我不会太强调。通常,我选择const非静态成员函数作为默认值,除非我有充分的理由不这样做

  • 如果客户端需要在没有实例的情况下调用它,则首选静态
  • 如果你不想把.h文件弄得乱七八糟,或者你想把它完全隐藏在.c文件中,你最好使用本地函数
  • 我想说:

    • 这可能无关紧要,所以与其说是“最佳实践”,不如说是“不要做任何疯狂的事情”
    • 如果类及其所有成员都是在其头中定义的,那么私有静态成员函数可能是最好的,因为它清楚地表明“不适用于客户端”。但对于非成员函数,有一些方法可以做到这一点:不要记录它,在注释中加上“不适用于客户端”,然后将整个内容粘贴在
      名称空间中,小心豹子的名称空间中
    • 如果类成员函数是在.cpp文件中定义的,那么像这样的小助手函数最好作为.cpp文件中的自由函数。静态名称空间或匿名名称空间
    一个静态成员函数,一个常量 非静态成员函数或局部 功能

    通常,它应该是另一个类的成员函数,或者至少是该类本身的非静态成员。 如果此函数仅从类的实例成员调用,则其逻辑含义可能需要一个实例,即使语法不需要。除了这个对象之外,任何东西都能提供有意义的参数或利用结果吗

    除非从对象实例外部调用此函数有意义,否则它不应该是静态的。除非在根本不访问类的情况下调用此函数是有意义的,否则它不应该是本地的

    借用Brian评论中的例子: 如果此函数更改全局状态,则它应该是全局状态类的成员; 如果此函数写入文件,则它应该是文件格式类的成员; 如果它正在刷新屏幕,它应该是。。。等
    即使它是一个简单的算术表达式,将其作为特定用途类的某些算术的成员(静态或非静态)也可能有用。

    将其作为非成员函数。

    共享代码不需要访问类的任何成员

    作为一般规则,如果一段代码不需要访问类的任何成员,请不要将其作为成员函数!尽可能多地封装类

    我建议在单独的名称空间中执行一个非成员函数,该函数将调用公共方法,然后调用为共享代码创建的函数

    以下是我的意思的一个例子:

    namepsace Astuff{
      class A{...};
    
      void sharedPart(){...};
    
      void first(const A& a);
      void second(const A& a);
    }
    
    void Astuff::first(const A& a){
       a.first();
       sharedPart();
    }
    

    使其成为非成员非好友函数。Scott Meyer对此有很好的解释(也有有效的C++第三版的第23条)。

    作为经验法则“尽量保持它的局部性,但必要时可以看到”。 如果调用函数的所有代码都驻留在同一个实现文件中,这意味着将其保留在实现文件的本地

    如果将其作为类的私有静态方法,则包括类在内的实现将无法调用它,但它们仍然可以看到它。因此,每次更改该方法的语义时,包括调用在内的所有实现都必须重新编译——这是一个相当大的负担,因为从他们的角度来看,他们甚至不需要知道这些语义

    因此,为了最大限度地减少不必要的依赖关系,您需要将其设置为静态全局函数

    但是,如果您发现自己在多个实现文件中重复此全局函数,则应该将该函数移动到单独的头文件/实现文件对中,以便所有调用方都可以包含它

    无论您是将该函数放置在名称空间中、全局范围内,还是将其作为类中的静态函数,都完全取决于您的喜好

    最后,如果您要使用全局静态函数,那么会有一个“更多C++”的版本:匿名命名空间。它有一个很好的特性,它可以实际存储状态,还可以防止用户甚至可以向前声明它的任何函数

    // in your .cpp file
    namespace /*anonymous*/
    {
       void foo()
       {
         // your code here
       }
    };
    
    void MyClass::FooUser1() { foo(); }
    void MyClass::FooUser2() { foo(); }
    

    我更喜欢将其设置为非成员函数(可能隐藏在子名称空间中,以清楚地表明它不应该是成员函数)