Правильний спосіб визначення методів простору імен C ++ у файлі .cpp


108

Можливо, дублікат, але не простий для пошуку ...

Дано заголовок типу:

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

Чи є "правильний" спосіб це зробити? Чи є якісь із цих «неправильних» у тому, що вони не означають одне і те ж?


У більшості кодів я зазвичай бачу третю версію (але я не знаю чому: D), друга версія просто протилежна тому, чому вводяться простори імен.
МістерАнубіс

1
Як і в цікавому факті, інструменти рефакторингу Visual Assist із задоволенням створюють код, використовуючи або №1, або №3, залежно від того, який стиль вже використовується в цільовому файлі.
Пан Хлопчик

Відповіді:


51

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

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

Версія 3 вірна ще й тому, що ви використовували ::оператор роздільної здатності для позначення MyClass::method ()в просторі іменns1 . Я віддаю перевагу версії 3.

Див. " Простіри імен" (C ++) . Це найкращий спосіб зробити це.


22
Називати №2 "неправильним" - це величезне перебільшення. За цією логікою всі назви символів є "неправильними", оскільки вони можуть приховати інші імена символів в інших областях.
десять четвертих

Це нелогічно. Він буде складати чудово (вибачте, міс пояснив, що у відповіді), але чому б ви визначили функцію поза її простором імен? Це бентежить читача. Крім того, коли використовується багато просторів імен, це не показує, до якого простору імен належить MyClass. Версії 1 і 3 вирішують цю проблему. На закінчення це не помиляється, а просто незрозуміло і заплутано.
GILGAMESH

3
Я погоджуюся з @PhoenicaMacia, використання трюку є жахливим і може призвести до плутанини. Розгляньте клас, який реалізує оператора як вільну функцію, у заголовку, який ви мали б namespace N {struct X { void f(); }; X operator==( X const &, X const & ); }, тепер у файлі cpp із використанням оператора ви можете визначити функцію-члена як void X::f() {}, але якщо ви визначите, X operator==(X const&, X const&)ви будете визначати іншого оператора від одного визначений у заголовку (для вільної функції вам доведеться використовувати або 1, або 3).
Девід Родрігес - дрибес

1
Зокрема, я віддаю перевагу 1, а приклад у зв’язаній статті насправді нічого не вирішує, перший приклад використовує 1, другий використовує суміш 1 і 3 (функції визначені кваліфікацією, але вони визначені всередині зовнішнього простору імен)
David Rodríguez - dribeas

1
З 3 я б сказав 1) найкраще, однак у більшості IDE є досить прикрою звичкаю відступати все, що знаходиться у цій декларації простору імен, і це додає певної плутанини.
locka

28

Через 5 років, і я думав, що я згадаю це, що і виглядає добре, і не є злим

using ns1::MyClass;

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

3
Це найкраща відповідь. Це виглядає найчистішим і уникає проблем з версією 1 OP, яка може ненавмисно вносити речі в простір імен і 2, які можуть ненавмисно вносити речі в глобальний простір.
ayane_m

Так, це чудова комбінація з меншим типізацією, ніж 3, хоча явно декларує наміри.
jb

14

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

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

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

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


1
Хоча я думаю , що «це краще , так що я не хвилює , якщо це збиває з пантелику людей , » логіка хибна, я повинен погодитися , що це є хорошим підходом для просторів імен.
Пан Хлопчик

1
+1 за чудову ідею "чому-не-думаю-що"! (Що стосується "людей не звикли до [нових технічно чудових речей]", вони
звикнуть

Просто для того, щоб переконатися, що я розумію, чи є вони outerі innerвизначені як простори імен в інших файлах заголовка?
dekuShrub

4

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



3

Я вибираю Num.3 (він же багатослівна версія). Це більше вводити текст, але наміри точні саме вам і компілятору. Проблема, яку ви опублікували як справді, насправді простіша, ніж реальний світ. У реальному світі існують інші сфери визначення, а не лише члени класу. Ваші визначення не дуже складні лише для класів - тому що їх сфера дії ніколи не відкривається (на відміну від просторів імен, глобальної області застосування тощо).

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

Num.2 Це дуже крихко, особливо у великих кодових базах - у міру зміни заголовків та залежностей ваша програма не зможе зібрати.

Num.3 Це ідеально, але дуже багато набрати - який ваш намір - щось визначити . Це робиться саме так, і компілятор запускає, щоб переконатися, що ви не помилилися, визначення не збігається з його декларацією тощо.


3

Виявляється, це не лише "матерія в стилі кодування". Число 2 призводить до помилки посилання при визначенні та ініціалізації змінної, оголошеної зовнішньою формою у файлі заголовка. Погляньте на приклад мого запитання. Визначення константи в просторі імен у файлі cpp


2

Усі способи правильні, і кожен має свої переваги та недоліки.

У версії 1 ви маєте перевагу в тому, що не потрібно писати простір імен перед кожною функцією. Недоліком є ​​те, що ви отримаєте нудне ідентифікацію, особливо якщо у вас є більше одного простору імен.

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

У версії 3 вам доведеться вводити більше, і ваші функціональні лінії можуть бути більшими за екран, що погано впливає на дизайн.

Є й інший спосіб, яким деякі користуються. Це схоже на першу версію, але без проблем з ідентифікацією.

Це так:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 }

OPEN_NS1

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

CLOSE_NS1

Ви самі вирішите вибрати, який краще для кожної ситуації =]


14
Я не бачу причин використовувати тут макрос. Якщо ви не хочете відступати, просто не відступайте. Використання макросу просто робить код менш очевидним.
десять четвертого

1
Я думаю, що остання названа вами версія корисна всякий раз, коли ви хочете скласти код зі старими компіляторами, які не підтримують простори імен (так, деякі динозаври все ще існують). У цьому випадку ви можете помістити макрос всередину #ifdefпропозиції.
Лука Мартіні

Вам не потрібно ідентифікувати, якщо ви не хочете, але якщо ви не використовуєте макроси, деякі IDE намагатимуться зробити це за вас. Наприклад, у Visual Studio ви можете вибрати весь код і натиснути ALT + F8 для автоматичного ідентифікації. Якщо ви не використовуєте визначення, ви втратите цю функціональність. Крім того, я не думаю, що OPEN_ (простір імен) та CLOSE_ (простір імен) менш очевидні, якщо вони є у вашому стандарті кодування. Причина @LucaMartini також цікава.
Ренан Грінерт

Якщо це робилося загальним, тобто #define OPEN_NS(X)я думаю, що це трохи корисно, але насправді ... я не заперечую проти макросів, але це здається трохи OTT. Я думаю, що підхід Дітмара Кюля краще для вкладених просторів імен.
Пан Хлопчик
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.