简体   繁体   English

'Helper'在C ++中的功能

[英]'Helper' functions in C++

While refactoring some old code I have stripped out a number of public methods that should actually of been statics as they a) don't operate on any member data or call any other member functions and b) because they might prove useful elsewhere. 在重构一些旧代码时,我已经删除了一些实际上应该是静态的公共方法,因为它们a)不对任何成员数据进行操作或调用任何其他成员函数和b)因为它们可能在其他地方证明是有用的。

This led me to think about the best way to group 'helper' functions together. 这让我想到了将“帮助”功能组合在一起的最佳方法。 The Java/C# way would be to use a class of static functions with a private constructor, eg: Java / C#方式是将一类静态函数与私有构造函数一起使用,例如:

class Helper  
{  
private:  
  Helper() { }
public:  
  static int HelperFunc1();  
  static int HelperFunc2();  
};

However, being C++ you could also use a namespace: 但是,作为C ++,您还可以使用命名空间:

namespace Helper  
{  
  int HelperFunc1();  
  int HelperFunc2();  
}

In most cases I think I would prefer the namespace approach but I wanted to know what the pros and cons of each approach are. 在大多数情况下,我认为我更喜欢命名空间方法,但我想知道每种方法的优缺点。 If used the class approach for example, would there be any overheads? 例如,如果使用类方法,是否会有任何开销?

Overhead is not an issue, namespaces have some advantages though 开销不是问题,命名空间虽然有一些优点

  • You can reopen a namespace in another header, grouping things more logically while keeping compile dependencies low 您可以在另一个头中重新打开命名空间,在保持编译依赖性较低的同时更加逻辑地对事物进行分组
  • You can use namespace aliasing to your advantage (debug/release, platform specific helpers, ....) 您可以使用命名空间别名来优势(调试/发布,特定于平台的帮助程序,......)

    eg I've done stuff like 我做过类似的事情

     namespace LittleEndianHelper { void Function(); } namespace BigEndianHelper { void Function(); } #if powerpc namespace Helper = BigEndianHelper; #elif intel namespace Helper = LittleEndianHelper; #endif 

A case where one might use class (or struct ) over namespace is when one needs a type, for example: 可以在namespace使用class (或struct )的情况是当需要类型时,例如:

struct C {
  static int f() { return 33; }
};

namespace N {
  int f() { return 9; }
}

template<typename T>
int foo() {
  return T::f();
}

int main() {
  int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
  return ret;
}

To add to Pieter's excellent response, another advantage of namespaces is that you can forward declare stuff that you put in a namespace somewhere else, especially structs... 为了增加Pieter的出色响应,命名空间的另一个优点是你可以转发声明你放在其他地方的命名空间中的东西,尤其是结构...

//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
  struct bar {/* ... */);
};

//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
  //...
  DoSomething(foo::bar);
};

And with namespaces... 并使用命名空间......

//Header a.h
// Big header files
namespace foo
{
  struct bar {/* ... */);
}

//header b.h
// Avoid include, instead forward declare 
//  (can put forward declares in a _fwd.h file)
namespace foo
{
  struct bar;
}

class b
{
  //...
  // note that foo:bar must be passed by reference or pointer
  void DoSomething(const foo::bar & o);
};

Forward declares make a big difference to your compile times after small header changes once you end up with a project spanning hundreds of source files. 一旦你最终得到一个跨越数百个源文件的项目,转发声明会在小标题更改后对编译时间产生很大影响。

Edit from paercebal 从paercebal编辑

The answer was too good to let it die because of an enum error (see comments). 由于枚举错误,答案太好了,不能让它死掉(见评论)。 I replaced enums (which can be forward-declared only in C++0x, not in today C++) by structs. 我用结构替换了枚举(只能在C ++ 0x中进行前向声明,而不是在今天的C ++中)。

The main advantage to using a namespace is that you can reopen it and add more stuff later, you can't do that with a class. 使用命名空间的主要优点是你可以重新打开它并在以后添加更多东西,你不能用类来做。 This makes this approach better for loosely coupled helpers (for example you could have a Helpers namespace for your entire library, much like all of STL is in ::std) 这使得这种方法更适合松散耦合的助手(例如,您可以为整个库创建一个Helpers名称空间,就像所有STL在:: std中一样)

The main advantage of a class is that you can nest it inside the class using it, you can't nest a namespace in a class. 类的主要优点是可以使用它将它嵌套在类中,不能在类中嵌套命名空间。 This makes this approach better for tightly coupled helpers. 这使得这种方法更适合紧密耦合的助手。

You won't have any extra overhead having them in a class vs a namespace. 在类和命名空间中,它们不会有任何额外的开销。

Copied/trimmed/reworked part of my answer from How do you properly use namespaces in C++? 复制/修剪/重写我的答案部分如何正确使用C ++中的命名空间? .

Using "using" 使用“使用”

You can use "using" to avoid repeating the "prefixing" of your helper function. 您可以使用“使用”来避免重复辅助函数的“前缀”。 for example: 例如:

struct AAA
{
   void makeSomething() ;
} ;

namespace BBB
{
   void makeSomethingElse() ;
}

void willCompile()
{
   AAA::makeSomething() ;
   BBB::makeSomethingElse() ;
}

void willCompileAgain()
{
   using BBB ;

   makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}

void WONT_COMPILE()
{
   using AAA ; // ERROR : Won't compile

   makeSomething() ; // ERROR : Won't compile
}

Namespace Composition 命名空间组合

Namespaces are more than packages. 命名空间不仅仅是包。 Another example can be found in Bjarne Stroustrup's "The C++ Programming Language". 另一个例子可以在Bjarne Stroustrup的“The C ++ Programming Language”中找到。

In the "Special Edition", at 8.2.8 Namespace Composition , he describes how you can merge two namespaces AAA and BBB into another one called CCC. 8.2.8命名空间组合的“特别版”中,他描述了如何将两个名称空间AAA和BBB合并到另一个名为CCC的名称空间中。 Thus CCC becomes an alias for both AAA and BBB: 因此,CCC成为AAA和BBB的别名:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

You could even import select symbols from different namespaces, to build your own custom namespace interface. 您甚至可以从不同的命名空间导入选择符号,以构建您自己的自定义命名空间界面。 I have yet to find a practical use of this, but in theory, it is cool. 我还没有找到它的实际用途,但从理论上讲,它很酷。

Namespaces offer the additional advantage of Koenig lookup. 命名空间提供了Koenig查找的额外优势。 Using helper classes may make your code more verbose - you usually need to include the helper class name in the call. 使用帮助程序类可能会使您的代码更加冗长 - 您通常需要在调用中包含帮助程序类名称。

Another benefit to namespaces is in readability later on. 命名空间的另一个好处是可读性。 With classes, you need to include words like "Helper" to remind you later that the particular class isn't used to create objects 对于类,您需要包含“Helper”之类的单词,以便稍后提醒您特定类不用于创建对象

In practice, there's no overhead in either. 在实践中,两者都没有开销。 After compilation, only the name mangling used differs. 编译后,只使用名称修改不同。

I tend to use anonymous namespaces when creating helper functions. 在创建辅助函数时,我倾向于使用匿名命名空间。 Since they should (generally) only be seen by the module that cares about them, its a good way to control dependencies. 因为它们(通常)只能由关心它们的模块看到,所以它是控制依赖关系的好方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM