默认情况下,使用命名空间函数。
类是用来构建对象的,而不是用来替换命名空间的。
在面向对象的代码中
Scott Meyers 在他的《Effective C++》一书中就这个主题写了一个完整的条目,“优先选择非成员非友元函数而不是成员函数”。我在 Herb Sutter 的一篇文章中找到了对这一原则的在线参考:http://www.gotw.ca/gotw/084.htm http://www.gotw.ca/gotw/084.htm
重要的是要知道:在 C++ 中,与类位于同一命名空间中并且以该类作为参数的函数属于该类的接口(因为ADL http://en.wikipedia.org/wiki/Argument_dependent_name_lookup将在解析函数调用时搜索这些函数)。
例如:
- 假设你有一个命名空间N
- 假设你有课C,在命名空间中声明N (换句话说,它的全名是N::C)
- 假设你有一个函数F,在命名空间中声明N (换句话说,它的全名是N::F)
- 假设这个函数F在其参数中,有一个类型的参数C
... 然后N::F是其一部分N::C的公共接口。
命名空间函数,除非声明为“friend”,否则无法访问类的内部结构,而静态方法有权访问类的内部结构。
这意味着,例如,在维护类时,如果需要更改类的内部结构,则需要在其所有方法(包括静态方法)中搜索副作用。
扩展一
将代码添加到类的接口。
在 C# 中,即使您无权访问类,也可以向类添加方法。但在C++中,这是不可能的。
但是,在 C++ 中,您仍然可以添加命名空间函数,甚至可以添加到某人为您编写的类中。
从另一方面来看,这在设计代码时很重要,因为通过将函数放在命名空间中,您将授权用户增加/完成类的接口。
扩展二
上一点的副作用是,不可能在多个标头中声明静态方法。每个方法都必须在同一个类中声明。
对于命名空间,可以在多个标头中声明来自同一命名空间的函数(几乎标准的交换函数就是最好的例子)。
扩展三
命名空间的基本优点是,在某些代码中,如果使用关键字,则可以避免提及它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
您甚至可以将“污染”限制为一类:
#include <string>
#include <vector>
{
using std::string ;
string s ; // Ok
vector v ; // COMPILATION ERROR
}
string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR
为了正确使用几乎标准的交换习惯用法,此“模式”是必需的。
这对于类中的静态方法来说是不可能做到的。
因此,C++ 命名空间有自己的语义。
但它更进一步,因为您可以以类似于继承的方式组合名称空间。
例如,如果您有一个命名空间A
有一个函数AAA
,一个命名空间B
有一个函数BBB
,你可以声明一个命名空间C
,并带来AAA
and BBB
在此名称空间中使用关键字using
.
您甚至可以将命名空间的完整内容放入另一个命名空间中,使用using 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();
}
结论
命名空间是为了命名空间而存在的。
上课是为了上课。
C++ 的设计使得每个概念都是不同的,并且在不同的情况下以不同的方式使用,作为不同问题的解决方案。
当需要命名空间时不要使用类。
就您而言,您需要命名空间。