Правильный способ определения методов пространства имен С++ в файле .cpp

Возможно, дубликат, но не простой поиск...

Учитывая заголовок как:

namespace ns1
{
 class MyClass
 {
  void method();
 };
}

Я вижу method(), определенный несколькими способами в файле .cpp:

Версия 1:

namespace ns1
{
 void MyClass::method()
 {
  ...
 }
}

Версия 2:

using namespace ns1;

void MyClass::method()
{
 ...
}

Версия 3:

void ns1::MyClass::method()
{
 ...
}

Есть ли "правильный" способ сделать это? Являются ли какие-либо из этих "неправильных" тем, что они не все означают одно и то же?

Ответ 1

Версия 2 неясна и не понятна, потому что вы не знаете, к какому пространству имен MyClass принадлежит, и это просто нелогично (функция класса не в том же пространстве имен?)

Версия 1 правильная, потому что она показывает, что в пространстве имен вы определяете функцию.

Версия 3 правильна также потому, что вы использовали оператор разрешения области :: для ссылки на MyClass::method () в пространстве имен ns1. Я предпочитаю версию 3.

См. Пространства имен (С++). Это лучший способ сделать это.

Ответ 2

Я использую версию 4 (см. ниже), потому что она сочетает в себе большинство преимуществ версии 1 (кратности ресоэффективного определения) и версии 3 (максимально явная). Основным недостатком является то, что люди не привыкли к этому, но поскольку я считаю его технически превосходящим альтернативы, я не против.

Версия 4: используйте полную квалификацию с использованием псевдонимов пространства имен:

#include "my-header.hpp"
namespace OI = outer::inner;
void OI::Obj::method() {
    ...
}

В моем мире я часто использую псевдонимы пространства имен, поскольку все явно квалифицировано - если оно не может (например, имена переменных) или оно является известной точкой настройки (например, swap() в шаблоне функции).

Ответ 3

5 лет спустя, и я подумал, что упомянул об этом, который оба выглядит красивым и не злым.

using ns1::MyClass;

void MyClass::method()
{
  // ...
}

Ответ 4

Версия 3 делает связь между классом и пространством имен очень явным за счет большей типизации. Версия 1 избегает этого, но фиксирует связь с блоком. Версия 2 имеет тенденцию скрывать это, поэтому я бы избегал этого.

Ответ 5

Оказывается, это не только "предмет в стиле кодирования". Num. 2 приводит к ошибке связывания при определении и инициализации объявленной переменной extern в файле заголовка. Взгляните на пример в моем вопросе. Определение константы в пространстве имен в файле cpp

Ответ 6

Все способы правильные, и каждый из них имеет свои преимущества и недостатки.

В версии 1 у вас есть преимущество в том, что вам не нужно писать пространство имен перед каждой функцией. Недостатком является то, что вы получите скучную идентификацию, особенно если у вас более одного уровня пространств имен.

В версии 2 вы делаете свой код более чистым, но если в CPP реализовано более одного пространства имен, можно напрямую обращаться к другим функциям и переменным, что делает ваше пространство имен бесполезным (для этого файла cpp).

В версии 3 вам нужно будет ввести больше, а ваши функциональные строки могут быть больше, чем экран, что плохо для дизайнерских эффектов.

Существует и другой способ использования некоторыми людьми. Это похоже на первую версию, но без проблем идентификации.

Это так:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 }

OPEN_NS1

void MyClass::method()
{
...
}

CLOSE_NS1

Вам решать, какой из них лучше для каждой ситуации =]

Ответ 7

Я выбираю Num.3 (a.k.a. verbose version). Это больше печатает, но намерение точно для вас и для компилятора. Проблема, которую вы разместили как есть, на самом деле проще, чем реальный мир. В реальном мире существуют другие области определения, а не только члены класса. Ваши определения не очень сложны только для классов - потому что их область никогда не открывается (в отличие от пространств имен, глобальной области видимости и т.д.).

Num.1 это может завершиться неудачно с областями, отличными от классов, - все, что может быть вновь открыто. Таким образом, вы можете объявить новую функцию в пространстве имен, используя этот подход, или ваши встроенные строки могут быть заменены через ODR. Вам понадобится это для некоторых определений (в частности, специализированных шаблонов).

Num.2 Это очень хрупко, особенно в больших кодовых базах - при смещении заголовков и зависимостей ваша программа не сможет скомпилироваться.

Num.3 Это идеальное, но многого типа - то, что вы намерены определить. Это делает именно это, и компилятор запускается, чтобы убедиться, что вы не допустили ошибку, определение не синхронизируется с его объявлением и т.д.