C ++ использует пространства имен, чтобы избежать длинных путей - PullRequest
2 голосов
/ 02 апреля 2009

Я все еще изучаю C ++, и я никогда прежде не создавал свои собственные пространства имен. Я экспериментировал с ними, и в то время как я заставил большинство вещей работать, есть одна вещь, которую я все еще не могу сделать. Я хотел бы иметь возможность вызывать статический метод внутри класса, не набирая что-то вроде NameOfClass::method. Вот то, что я думал, что код должен выглядеть, но он не компилируется:

Файл A.h,

namespace Test
{
    class A
    {
        public:
            static int foo() { return 42; }
    };
}

Файл main.cpp,

#include <iostream>

#include "A.h"

using namespace std;
using namespace Test::A;

int main()
{
    cout << foo() << endl;

    return 0;
}

Компилятор выдаёт мне:

main.cpp:6: error: ‘A’ is not a namespace-name
main.cpp:6: error: expected namespace-name before ‘;’ token
main.cpp: In function ‘int main()’:
main.cpp:10: error: ‘foo’ was not declared in this scope

Можно ли сделать то, что я пытаюсь сделать, не набрав A::foo?

Ответы [ 4 ]

10 голосов
/ 02 апреля 2009

В C ++ вы / особенно / должны внимательно читать сообщения об ошибках компилятора.

Обратите внимание, что первой ошибкой было «ошибка:« A »не является именем пространства имен». Это правда, А это имя класса.

using namespace Foo; // brings in  all of foo;
using Bar::Baz // brings in only Baz from Bar

Вы хотите написать:

using Test::A;

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

Однако, поскольку foo является статическим в A, вам все равно придется явно ссылаться на A :: foo. (Если вы не делаете что-то вроде написания бесплатной функции, которая пересылает A :: foo; в общем, это плохая идея, если вы делаете это только для того, чтобы сохранить некоторую типизацию.)

Некоторые могут посоветовать вообще не использовать объявления, а полностью указывать все имена.

Но это (цитируя Страуструпа) «утомительно и подвержено ошибкам», и это мешает рефакторингу: скажем, что вы полностью квалифицируете каждое использование класса FooMatic :: Stack, а затем руководство настаивает прямо перед вами » собирается начать производство, вы используете очень похожий класс стека BarMatic, потому что barMatic только что выкупили вашу компанию.

Если бы вы были повсюду полностью квалифицированы, вы бы много перепрыгивали, надеясь, что ваше регулярное выражение было правильным. Если вы использовали декларацию using, вы можете просто исправить свой (надеюсь, общий) заголовочный файл. Таким образом, объявление using очень похоже на «typedef int ourInt;» или манифест-константа или const: "const int FOO = 1;" в том смысле, что она предоставляет одно место для изменения того, что упоминается во многих местах. Полное определение пространства имен при каждом использовании лишает этой выгоды.

И наоборот, если бы вы использовали директиву using и внесли все пространство имен FooMatic, ваш grep мог бы быть еще сложнее, если, скажем, руководство настаивало на BarMatic :: Foo, но вы все равно должны были использовать FooMatic: Baz, эквивалент BarMatic для Баз по какой-то причине непригоден для использования.

Таким образом, ввод одного типа (класса, функции, константы) за один раз, как правило, является наиболее гибким способом наилучшей защиты от неизбежных, но пока неизвестных изменений. Как и в большинстве кодов, вы хотите минимизировать утомительное повторение при сохранении достаточной детализации.

5 голосов
/ 02 апреля 2009

Обойти это невозможно, нужно указать имя класса для статических методов.

using namespace Test;

Тогда:

int answerToEverything = A::foo();
0 голосов
/ 02 апреля 2009

Не будьте обидчиком "использующего пространства имен". Используйте эти пространства имен!

std::cout << Test::A::foo() << std::endl;
0 голосов
/ 02 апреля 2009

Нет, невозможно делать то, что ты пытаешься делать элегантным способом. Самое близкое, что вы сможете сделать, - это создать макрос или встроенную функцию, которая делегирует вашу функцию. Однако обе эти альтернативы довольно безобразны, поэтому я не собираюсь публиковать примеры кода. Просто откусите маркер и укажите полное имя или измените код, чтобы статические методы были просто глобальными функциями.

...