С++: Пространства имен - Как правильно использовать в заголовке и исходных файлах?
Рассмотрим пару двух исходных файлов: файл декларации интерфейса (*.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() { ... }
}
Мой вопрос: Есть ли какие-то различия между этими двумя практиками и считается лучше других?
Ответы
Ответ 1
С точки зрения читаемости кода, вероятно, лучше, по-моему, использовать метод №2 по этой причине:
Вы можете быть using
несколькими пространствами имен за раз, а любой объект или функция, написанные ниже этой строки, могут принадлежать любому из этих пространств имен (запрет конфликтов имен). Обтекание всего файла в блоке namespace
более явственно и позволяет объявлять новые функции и переменные, которые принадлежат этому пространству имен в файле .cpp, а также
Ответ 2
Самый ясный вариант, который вы не показывали:
int MyNamespace::MyClass::foo()
{
// ...
}
Это также очень многословно; слишком много для большинства людей. Поскольку using
namespace
является приемом для конфликтов имен, по крайней мере, по моему опыту,
и его следует избегать, за исключением очень ограниченных областей и мест, я
обычно используйте ваш # 2.
Ответ 3
Существуют ли различия между этими двумя практиками
Да. # 1 и # 2 являются примерами using-directive и определение пространства имен соответственно. В этом случае они практически одинаковы, но имеют другие последствия. Например, если вы вводите новый идентификатор рядом с MyClass::foo
, он будет иметь другую область:
# 1:
using namespace MyNamespace;
int x; // defines ::x
# 2:
namespace MyNamespace {
int x; // defines MyNamespace::x
}
считается лучшим, чем другим?
# 1 Плюсы: немного более кратки; сложнее случайно ввести что-то в MyNamespace
невольно. Минусы: непреднамеренно вытягивать существующие идентификаторы.
# 2 Плюсы: более ясно, что определения существующих идентификаторов и декларации новых идентификаторов принадлежат MyNamespace
. Минусы: проще непреднамеренно ввести идентификаторы в MyNamespace
.
Критика как # 1, так и # 2 состоит в том, что они относятся ко всему пространству имен, когда вы, вероятно, заботитесь только об определении членов MyNamespace::MyClass
. Это тяжело, и он плохо сообщает о намерениях.
Возможной альтернативой # 1 является using-declaration, которая включает только интересующий вас идентификатор:
#include "MyClass.h"
using MyNamespace::MyClass;
int MyClass::foo() { ... }
Ответ 4
Я хотел бы также добавить, что если вы решите по какой-то причине реализовать специализированную специализацию в файле cpp и просто положитесь на using namespace
, вы столкнетесь с следующей проблемой:
// .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(){}
В противном случае, если вы примените метод # 2, это будет нормально.
Ответ 5
Я хотел бы добавить еще один способ, используя using-declaration:
#include "MyClass.h"
using MyNamespace::MyClass;
int MyClass::foo() { ... }
Таким образом, вы не можете многократно вводить имя пространства имен, если у класса есть много функций