哪一个最重要的代码?

时间:2009-06-25 11:46:36

标签: c++

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

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

void A::Second()
{
   secondFunctionEpilogue();
   sharedPart();
}

目前firstFunctionEpilogue()secondFunctionEpilogue()sharedPart()不是函数调用,只是代码段,sharedPart()代码是重复的。我想摆脱重复。

共享代码片段不需要访问该类的任何成员。所以我可以把它作为三个中的任何一个来实现:

  • 静态成员函数,
  • const非静态成员函数或
  • 本地功能。

哪种变体更好,为什么?

7 个答案:

答案 0 :(得分:5)

如果您的函数访问状态但未更改它,则使用const成员函数。

您的情况:

如果你的函数1)不需要访问代码的任何成员,并且2)与该类相关,那么将它作为你的类的静态函数。

很明显,它不是修改状态,也不是基于对象的状态。

您未提及的额外案例:

还有另外一件事你也可以做。这就是让你的SharedPart接受一个成员函数指针并调用它然后处理它的主体。如果你有很多First(),Second(),Third(),Fourth(),......这样的函数,那么这可以减少代码重复。这样你就不需要继续调用SharedPart();在每个成员函数的末尾,你可以重用First(),Second(),THird(),...而无需调用代码的SharedPart()。

答案 1 :(得分:3)

我会说:

  • 这可能没关系,所以它不是“最佳实践”,而是“只是不要做任何疯狂的事情”。
  • 如果类及其所有成员都在其标题中定义,那么私有静态成员函数可能是最好的,因为它清楚地表明“不适用于客户端”。但是有一些方法可以为非成员函数执行此操作:不要记录它,将评论“放在客户端”,并将整个内容放在namespace beware_of_the_leopard中。
  • 如果类成员函数是在.cpp文件中定义的,那么像这样的小帮助函数最好是.cpp文件中的自由函数。静态或匿名命名空间。

答案 2 :(得分:1)

或者它可能属于不同的类别。

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

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

  1. 如果客户需要在没有实例的情况下调用它,则首选静态
  2. 如果您不想混淆.h文件或希望它完全隐藏在.c
  3. 中,请选择本地功能

答案 3 :(得分:1)

将其设为非会员功能

共享代码片段不需要访问该类的任何成员。

作为一般规则,如果一段代码不需要访问该类的任何成员,则不要使其成为成员函数!尝试尽可能地封装你的类。

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

这是我的意思的一个例子:

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();
}

答案 4 :(得分:0)

  

一个静态成员函数,一个const   非静态成员函数或本地   功能

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

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

借用Brian的评论中的例子: 如果此函数改变全局状态,它应该是一个全局状态类的成员; 如果此函数写入文件,则它应该是文件格式类的成员; 如果它是令人耳目一新的屏幕,它应该是......等的成员 即使它是一个简单的算术表达式,使它成为某些ArithmeticsForSpecificPurpose类的成员(静态或非静态)可能是有用的。

答案 5 :(得分:0)

使其成为非会员非朋友功能。 Scott Meyer对此here(以及Effective C ++ 3rd Edition的第23项)有一个很好的解释。

答案 6 :(得分:0)

根据经验,“尽量将其保持在本地,但必要时可以看到”。

如果调用该函数的所有代码都驻留在同一个实现文件中,这意味着将它保留在实现文件的本地。

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

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

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

无论是将该函数放置在命名空间中,还是放在全局范围内,还是作为类中的静态函数,都非常有用。

最后一点,如果你选择全局静态函数,那就是“更像c ++”的版本:匿名命名空间。它有一个很好的属性,它可以实际存储状态,也可以防止用户甚至转发声明它的任何功能。

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

void MyClass::FooUser1() { foo(); }
void MyClass::FooUser2() { foo(); }