столкновение имен в C ++ - PullRequest
       20

столкновение имен в C ++

3 голосов
/ 04 декабря 2009

При написании кода я столкнулся с этой проблемой:

<code>
#include <iostream></p>

<p>class random
{
 public:
 random(){ std::cout << "yay!! i am called \n" ;}
};</p>

<p>random r1 ;</p>

<p>int main()
{
 std::cout << "entry!!\n" ;
 static random r2;
 std::cout << "done!!\n" ;
 return 0 ;
}

Когда я пытаюсь скомпилировать этот код, я получаю сообщение об ошибке
error: ârandomâ does not name a type.
Когда я использую другое имя для класса, код работает нормально.
Похоже, random определено где-то еще (хотя сообщение компилятора не очень информативно).

Мой вопрос: как я могу убедиться, что используемое мной имя не конфликтует с именем, используемым во включенных файлах? Я пытался использовать пространства имен, но это приводит к неоднозначности во время вызова. Есть идеи?
[EDIT]
Я использовал пространства имен как using namespace myNSpace
Но когда я использовал его как use myNSpace::random, он работал нормально.

Ответы [ 10 ]

8 голосов
/ 04 декабря 2009

Использовать пространство имен

namespace myNamespace
{

    class random
    {
    public:
        random(){ std::cout << "yay!! i am called \n" ;}
    };

}

myNamespace::random r1;
5 голосов
/ 04 декабря 2009

Вы используете функцию POSIX random().

Как избежать столкновений? Знай свои библиотеки. Или вы можете сделать, как я, чтобы диагностировать это, скажем man random. Там это было, случайно (3).

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

4 голосов
/ 04 декабря 2009

В случае g ++ используйте параметр командной строки -ansi. Это удаляет нестандартную функцию random из stdlib.h.

По умолчанию g ++ компилируется как -std=gnu++98, что означает «Стандарт ISO C ++ 1998 года плюс поправки плюс расширения GNU». Так что ваш код не сделал ничего плохого, чтобы быть переносимым. Просто без -ansi вы не используете совместимый компилятор.

Эти функции stdlib BSD (и Posix) входят в число этих расширений GNU. Из документации glibc:

http://www.gnu.org/s/libc/manual/html_node/BSD-Random.html

"Использование этих функций с библиотекой GNU C не дает никаких преимуществ; мы поддерживаем их только для совместимости с BSD."

В общем, если вы хотите написать код, переносимый на несовместимые компиляторы, вам просто нужно запомнить особенности каждого отдельного компилятора в мире. GCC и MSVC хороши для начала. Даже с -ansi вы можете сделать gcc несовместимым с другими параметрами командной строки, такими как -O2. Это произошло с фиаско -fdelete-null-pointer-checks, которое некоторое время назад поражало ядро ​​Linux. То же самое касается платформ, библиотеки которых «расширяют» C (и, следовательно, C ++), таких как BSD и Posix.

Причина, по которой в первую очередь существует стандарт C, заключается в том, что вам не нужно беспокоиться об этом, и лично я считаю, что, к сожалению, другие стандарты портят стандартные заголовки C. Но я предполагаю, что факт наличия этих функций в stdlib на BSD датируется до C89. Если это так, то, по-видимому, это позволило избежать серьезных изменений в BSD и других Unix-системах в то время.

Кстати, я обнаружил, что random() был в stdlib.h с g++ -E, что полезно, когда вы хотите знать, что на самом деле системные заголовки делают с вашей программой. Я предполагал, что поиск в сети «случайных» будет бессмысленным. Но "stdlib random" работал довольно хорошо.

2 голосов
/ 04 декабря 2009

Почему ваш using namespace... не работает, а ваш using ... работает? Сначала я хочу показать вам другой способ решения этой проблемы с помощью разработанного спецификатора типа:

int main() {
  // ...
  static class random r2; // notice "class" here
  // ...
}

Это работает, потому что "class some_class" - это сложный спецификатор типа, который будет игнорировать любые объявления не-типов при поиске указанного вами имени, поэтому функция POSIX в глобальной области видимости, которая имеет то же имя, не будет скрывать имя класса Вы пытались решить эту проблему двумя другими способами: используя директивы и используя объявления:

  • Затем вы попытались вставить тип в пространство имен и попытались using namespace foo; в основном - почему это не сработало?

    namespace foo {
    class random
    {
     public:
     random(){ std::cout << "yay!! i am called \n" ;}
    };
    }
    
    int main() {
     using namespace foo; 
     static random r2; // ambiguity!
     return 0 ;
    }
    

    Вы можете спросить, почему это так, потому что вы могли подумать, что директива using объявляет имена foo в локальной области видимости main - но это не так. Это не объявление какого-либо имени, на самом деле это просто ссылка на другое пространство имен. В этом случае он делает имя видимым при поиске безоговорочного имени, но имя становится видимым как член пространства имен, включающего в себя директиву using и обозначенное пространство имен (foo). Это пространство имен является глобальным пространством имен.

    Итак, при поиске имени будут найдены два объявления этого имени - глобальное объявление POSIX random и объявление класса в foo. Объявления не были сделаны в одной и той же области (декларативной области), и поэтому имя функции не скрывает имя класса как обычно (см. man stat для примера, где это происходит), но результат является неоднозначным.

  • A используя объявление , однако объявляет одно имя как член декларативного региона, в котором оно появляется. Поэтому, когда random ищется, начиная с main, он сначала находит имя, которое ссылается на объявление random в foo, и это будет эффективно скрывать глобальную функцию POSIX. Так что следующие работы

    namespace foo {
    class random
    {
     public:
     random(){ std::cout << "yay!! i am called \n" ;}
    };
    }
    
    int main() {
     using foo::random; 
     static random r2; // works!
     return 0 ;
    }
    
2 голосов
/ 04 декабря 2009

Если у вас проблемы с именами, используйте пространство имен:

namespace mydata{
 class random{things};
}

А потом назовите это mydata::random;

2 голосов
/ 04 декабря 2009

Это выглядит как проблема с вашим конкретным компилятором. Это не выдает ошибку с компиляторами, которые мне пригодятся.

1 голос
/ 04 декабря 2009

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

Поместив свой символ в пространство имен, вы можете:

  • полное название: myNamespace::mySymbol(x);
  • явно разрешить неоднозначность: using myNamespace::mySymbol;

Обратите внимание, что извлечение всех символов из вашего пространства имен через using myNamespace; не помогает, поскольку это не устраняет неоднозначность.

Для полной квалификации принято использовать сокращенные имена:

namespace mns = myNamespace;
mns::mySymbol(x);
1 голос
/ 04 декабря 2009

Чтобы избежать этих проблем, используйте пространства имен .. wikipedia

namespace myNamespace
{
     class random
     {
         ....
     };
}
0 голосов
/ 04 декабря 2009

компилятор g ++, который я использую правильно скомпилировал и запустил вашу программу. Я использую MinGw 5.1.6 для запуска g ++ на Windows ..

0 голосов
/ 04 декабря 2009

Вы включаете cstdlib? Я получаю ошибку, которую вы показываете, когда включаю ее, я не вижу, если не включаю

...