Определение класса анонимного пространства имен - PullRequest
10 голосов
/ 18 июля 2009

Я просматривал некоторый (C ++) код и нашел что-то вроде этого:

//Foo.cpp
namespace
{
    void SomeHelperFunctionA() {}
    void SomeHelperFunctionB() {}
    void SomeHelperFunctionC() {}

    //etc...    

    class SomeClass //<---
    {
        //Impl
    };
}

SomeHelperFunction[A-Z] - это функции, которые нужны только в этом модуле перевода, поэтому я понимаю, почему они находятся в анонимном namespace. Точно так же SomeClass также требуется только в этой единице перевода, но у меня сложилось впечатление, что у вас могут быть классы с одинаковыми именами в разных единицах перевода без каких-либо коллизий именования при условии, что у вас нет глобального объявления класса например, в обычно включаемом заголовочном файле).

Я должен также упомянуть, что этот конкретный модуль перевода не включает в себя любые заголовки, которые могут объявлять класс с идентичным именем (SomeClass).

Итак, учитывая эту информацию, может кто-нибудь пролить свет на то, почему оригинальный программист мог это сделать? Возможно, в качестве меры предосторожности на будущее?

Честно говоря, я никогда раньше не видел классов, используемых в анонимных пространствах имен.

Спасибо!

Ответы [ 4 ]

6 голосов
/ 18 июля 2009

Анонимное пространство имен похоже на статическое ключевое слово, когда оно применяется на глобальном уровне.

Благодаря анонимному пространству имен вы не можете вызывать что-либо внутри пространства имен из другого файла.

Анонимные пространства имен позволяют ограничить область действия только текущим файлом.

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

Пример:

Файл: test.cpp

namespace 
{
  void A()
  {
  }
  void B()
  {
  }
  void C()
  {
  }
}

void CallABC()
{ 
  A();
  B();
  C();
}

Файл: main.cpp

void CallABC();//You can use ABC from this file but not A, B and C

void A()
{
//Do something different
}

int main(int argc, char** argv)
{
  CallABC();
  A();//<--- calls the local file's A() not the other file. 
  return 0;
}

Выше будет хорошо скомпилировано. Но если вы попытаетесь написать функцию CallABC() в своем основном файле, у вас будет ошибка компоновки.

Таким образом, вы не можете вызывать функции A(), B() и C() по отдельности, но вы можете вызвать CallABC(), который вызовет их все по порядку.

Вы можете переслать объявление CallABC() в вашем main.cpp и вызвать его. Но вы не можете переслать декларацию test.cpp's A (), B () или C () внутри вашего main.cpp, так как у вас будет ошибка компоновки.

Что касается того, почему внутри пространства имен есть класс. Чтобы убедиться, что внешние файлы не используют этот класс. Что-то внутри .cpp, вероятно, использует этот класс.

1 голос
/ 20 июля 2009

У меня сложилось впечатление, что у вас могут быть классы с одинаковыми именами в разных единицах перевода без каких-либо коллизий имен при условии, что у вас нет глобального объявления класса

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

1 голос
/ 19 июля 2009

В стандарте C ++ ISO (раздел 2.3) вы найдете правило под названием Правило единого определения .

Из-за сложной взаимосвязи между компиляцией и компоновкой в ​​C ++ это не очень простое правило. Большинство деталей здесь .

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

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

1 голос
/ 18 июля 2009

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

...