C + + : 命名空间——如何正确地在头文件和源文件中使用?

考虑两个源文件: 接口声明文件(*.h*.hpp)及其实现文件(*.cpp)。

*.h文件如下所示:

namespace MyNamespace {
class MyClass {
public:
int foo();
};
}

我见过在源文件中使用名称空间的两种不同做法:

*.cpp演示练习 # 1:

#include "MyClass.h"
using namespace MyNamespace;


int MyClass::foo() { ... }

*.cpp演示练习2:

#include "MyClass.h"
namespace MyNamespace {


int MyClass::foo() { ... }


}

我的问题是: 这两种做法之间有什么区别吗? 一种做法被认为比另一种做法更好吗?

76503 次浏览

From a code readability standpoint, it is probably better in my opinion to use the #2 method for this reason:

You can be using multiple namespaces at a time, and any object or function written below that line can belong to any of those namespaces (barring naming conflicts). Wrapping the whole file in a namespace block is more explicit, and allows you to declare new functions and variables that belong to that namespace within the .cpp file as well

The clearest is the option you didn't show:

int MyNamespace::MyClass::foo()
{
//  ...
}

It's also very verbose; too much so for most people. Since using namespace is a recipe for name conflicts, at least in my experience, and should be avoided except in very limited scopes and places, I generally use your #2.

Are there any differences between these two practices

Yes. #1 and #2 are examples of a using-directive and a namespace definition respectively. They are effectively the same in this case but have other consequences. For instance, if you introduce a new identifier alongside MyClass::foo, it will have a different scope:

#1:

using namespace MyNamespace;
int x;  // defines ::x

#2:

namespace MyNamespace {
int x;  // defines MyNamespace::x
}

is one considered better than the other?

#1 Pros: a little more terse; harder to accidentally introduce something into MyNamespace unwittingly. Cons: may pull in existing identifiers unintentionally.

#2 Pros: more clear that definitions of existing identifiers and declarations of new identifiers both belong to MyNamespace. Cons: easier to unintentionally introduce identifiers to MyNamespace.

A criticism of both #1 and #2 is that they are referring to an entire namespace when you probably only care about the definition of members of MyNamespace::MyClass. This is heavy-handed and it communicates the intent poorly.

A possible alternative to #1 is a using-declaration which includes only the identifier you're interested in:

#include "MyClass.h"
using MyNamespace::MyClass;


int MyClass::foo() { ... }

I'd like also to add that if you decide due to some reason to implement a template specialization in a cpp file and just rely on using namespace you will run into the following problem:

// .h file
namespace someNameSpace
{
template<typename T>
class Demo
{
void foo();
};
}


// .cpp file
using namespace someNameSpace;


template<typename T>
void Demo<T>::foo(){}


// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}

Otherwise if you apply #2 method this will be fine.

I'd like to add one more way, using a using-declaration:

#include "MyClass.h"
using MyNamespace::MyClass;


int MyClass::foo() { ... }

This saves you from typing the namespace name many times, if a class has many functions.

I think the practice #1 is not correct C++ code at all. This code snippet defines ::MyClass::foo symbol, where the real full qualified name is ::MyNamespace::MyClass::foo.

To learn about namespaces you can read section 7.3 of the draft let's say for standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf

This concept is pretty old from 1998 or so, so you can use any standard or books of B.Stroustroup to learn about it.

In C++ language the namespace is a named scope. The namespace, as opposed to the class definition, is open to adding new functions to it.

The construction "using namespace NS;" in C++ is called as using-directive, and it can be used for several goals in my practice:

  1. You can use this directive in another namespace to combine(mix) names from a different namespace.
  2. In the context of the compilation unit it appends synonyms to all variables in namespace NS.

To define symbol, you can use two mechanisms - you can use the explicit qualification with all namespaces via operating in global namespace in C++ source file.

Or You can open namespace and add definitions to it (practice #2).