命名空间 + 函数与类上的静态方法

2022-01-14 00:00:00 static-methods namespaces c++

假设我有或将要编写一组相关的函数.假设它们与数学有关.在组织上,我应该:

Let's say I have, or am going to write, a set of related functions. Let's say they're math-related. Organizationally, should I:

  1. 编写这些函数并将它们放在我的 MyMath 命名空间中,并通过 MyMath::XYZ()
  2. 引用它们
  3. 创建一个名为 MyMath 的类并将这些方法设为静态并引用类似的 MyMath::XYZ()
  1. Write these functions and put them in my MyMath namespace and refer to them via MyMath::XYZ()
  2. Create a class called MyMath and make these methods static and refer to the similarly MyMath::XYZ()

为什么我会选择其中一个来组织我的软件?

Why would I choose one over the other as a means of organizing my software?

推荐答案

默认使用命名空间函数.

类用于构建对象,而不是替换命名空间.

Classes are to build objects, not to replace namespaces.

Scott Meyers 为他的 Effective C++ 书写了一整篇关于这个主题的文章,Prefer non-member non-friend functions to member functions".我在 Herb Sutter 的一篇文章中找到了对这一原则的在线参考:http://www.gotw.ca/gotw/084.htm

Scott Meyers wrote a whole Item for his Effective C++ book on this topic, "Prefer non-member non-friend functions to member functions". I found an online reference to this principle in an article from Herb Sutter: http://www.gotw.ca/gotw/084.htm

要知道的重要一点是:在 C++ 中,与类在同一个命名空间中并且以该类作为参数的函数属于该类的接口(因为ADL 将在解析函数调用时搜索这些函数.

The important thing to know is that: In C++, functions that are in the same namespace as a class is, and that have that class as a parameter, belong to that class' interface (because ADL will search those functions when resolving function calls).

例如:

  • 假设您有一个命名空间N
  • 假设你有一个类 C,在命名空间 N 中声明(换句话说,它的全名是 N::C)
  • 假设你有一个函数 F,在命名空间 N 中声明(换句话说,它的全名是 N::F)
  • 假设函数 F 在其参数中具有 C
  • 类型的参数
  • let's say you have a namespace N
  • let's say you have a class C, declared in namespace N (in other words, its full name is N::C)
  • let's say you have a function F, declared in namespace N (in other words, its full name is N::F)
  • let's say that function F has, among its parameters, a parameter of type C

... 那么 N::F 是 N::C 的公共接口的一部分.

... Then N::F is part of N::C's public interface.

命名空间函数,除非声明为朋友",无权访问类的内部,而静态方法有.

Namespaced functions, unless declared "friend," have no access to the class' internals, whereas static methods have.

这意味着,例如,在维护类时,如果您需要更改类的内部结构,则需要在其所有方法中搜索副作用,包括静态方法.

This means, for example, that when maintaining your class, if you need to change your class' internals, you will need to search for side effects in all its methods, including the static ones.

向类的接口添加代码.

在 C# 中,即使您无权访问,也可以向类添加方法.但在 C++ 中,这是不可能的.

In C#, you can add methods to a class even if you have no access to it. But in C++, this is impossible.

但是,仍然在 C++ 中,您仍然可以添加命名空间函数,甚至可以添加到有人为您编写的类中.

But, still in C++, you can still add a namespaced function, even to a class someone wrote for you.

从另一方面看,这在设计代码时很重要,因为通过将函数放在命名空间中,您将授权您的用户增加/完成类的接口.

See from the other side, this is important when designing your code, because by putting your functions in a namespace, you will authorize your users to increase/complete the class' interface.

上一点的副作用,不可能在多个头文件中声明静态方法.每个方法都必须在同一个类中声明.

A side-effect of the previous point, it is impossible to declare static methods in multiple headers. Every method must be declared in the same class.

对于命名空间,来自同一个命名空间的函数可以在多个头文件中声明(几乎标准的交换函数就是最好的例子).

For namespaces, functions from the same namespace can be declared in multiple headers (the almost-standard swap function is the best example of that).

命名空间最酷的地方在于,在某些代码中,你可以避免提及它,如果你使用关键字using:

The basic coolness of a namespace is that in some code, you can avoid mentioning it, if you use the keyword using:

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

你甚至可以限制污染";到一个班级:

And you can even limit the "pollution" to one class:

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

这个模式"是正确使用几乎标准的交换习语所必需的.

This "pattern" is mandatory for the proper use of the almost-standard swap idiom.

而这对于类中的静态方法是不可能的.

And this is impossible to do with static methods in classes.

因此,C++ 命名空间有自己的语义.

So, C++ namespaces have their own semantics.

但它更进一步,因为您可以以类似于继承的方式组合命名空间.

But it goes further, as you can combine namespaces in a way similar to inheritance.

例如,如果你有一个命名空间 A 和一个函数 AAA,一个命名空间 B 和一个函数 BBB,可以声明一个命名空间C,并在这个命名空间中引入AAABBB关键字using.

For example, if you have a namespace A with a function AAA, a namespace B with a function BBB, you can declare a namespace C, and bring AAA and BBB in this namespace with the keyword using.

您甚至可以使用 using namespace 将一个命名空间的全部内容带入另一个命名空间,如命名空间 D 所示!

You can even bring the full content of a namespace inside another, with using namespace, as shown with namespace D!

namespace A
{
   void AAA();
   void AAA2();
}

namespace B
{
   void BBB();
}

namespace C
{
   using A::AAA;
   using B::BBB;
}

namespace D
{
   using namespace A;
   using namespace B;
}

void foo()
{
   C::AAA();
   // C::AAA2(); // ERROR, won't compile
   C::BBB();
}

void bar()
{
   D::AAA();
   D::AAA2();
   D::BBB();
}

结论

命名空间用于命名空间.类是为了类.

Conclusion

Namespaces are for namespaces. Classes are for classes.

C++ 的设计使每个概念都是不同的,并且在不同的情况下以不同的方式使用,作为不同问题的解决方案.

C++ was designed so each concept is different, and is used differently, in different cases, as a solution to different problems.

当你需要命名空间时不要使用类.

Don't use classes when you need namespaces.

在你的情况下,你需要命名空间.

And in your case, you need namespaces.

相关文章