Правильный способ определения методов пространства имен C ++ в файле .cpp - PullRequest
95 голосов
/ 30 декабря 2011

Вероятно, дубликат, но его нелегко найти ...

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

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()
{
 ...
}

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

Ответы [ 8 ]

44 голосов
/ 30 декабря 2011

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

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

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

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

23 голосов
/ 18 апреля 2016

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

using ns1::MyClass;

void MyClass::method()
{
  // ...
}
13 голосов
/ 30 декабря 2011

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

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

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

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

4 голосов
/ 30 декабря 2011

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

3 голосов
/ 18 января 2017

Руководство по стилю Googles C ++ диктует вашу версию 1 без отступов.

Googles C++ Style Guide for namespaces

3 голосов
/ 15 июля 2014

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

2 голосов
/ 30 декабря 2011

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

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

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

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

2 голосов
/ 30 декабря 2011

Все пути верны, и у каждого есть свои преимущества и недостатки.

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

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

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

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

Это так:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 }

OPEN_NS1

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

CLOSE_NS1

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

...