Пространство имен C ++ и включает - PullRequest
29 голосов
/ 23 декабря 2008

Зачем нам нужно использовать пространство имен и включать директивы в программах на C ++?

Например,

#include <iostream>

using namespace std;

int main() {
 cout << "Hello world";
}

Почему недостаточно просто иметь #include или просто "использовать пространство имен std" и избавиться от другого?

(я думаю о аналогии с Java, import java.net. * Импортирует import все с java.net вам больше ничего не нужно делать.)

Ответы [ 11 ]

39 голосов
/ 24 декабря 2008

использование директив и включение директив препроцессора - это две разные вещи. include примерно соответствует переменной среды CLASSPATH Java или опции -cp виртуальной машины Java.

То, что он делает, делает типы известными компилятору. Например, включение <string> позволит вам ссылаться на std::string:

#include <string>
#include <iostream>

int main() {
    std::cout << std::string("hello, i'm a string");
}

Теперь использование директив похоже на import в Java. Они делают имена видимыми в той области, в которой они появляются, поэтому вам больше не нужно полностью их квалифицировать. Как и в Java, используемые имена должны быть известны прежде, чем их можно будет сделать видимыми:

#include <string> // CLASSPATH, or -cp
#include <iostream>

// without import in java you would have to type java.lang.String . 
// note it happens that java has a special rule to import java.lang.* 
// automatically. but that doesn't happen for other packages 
// (java.net for example). But for simplicity, i'm just using java.lang here.
using std::string; // import java.lang.String; 
using namespace std; // import java.lang.*;

int main() {
    cout << string("hello, i'm a string");
}

Это плохая практика - использовать директиву using в заголовочных файлах, потому что это означает, что любой другой исходный файл, который включает его, будет видеть эти имена, используя поиск без определения имени. В отличие от Java, где вы делаете имена видимыми только для пакета, в котором появляется строка импорта, в C ++ это может повлиять на всю программу, если они включают этот файл прямо или косвенно.

Будьте осторожны, когда делаете это в глобальном масштабе, даже в файлах реализации. Лучше использовать их как можно более локально. Для пространства имен std я никогда не использую это. Я и многие другие люди просто пишем std:: перед именами. Но если вам случится это сделать, сделайте это так:

#include <string>
#include <iostream>

int main() {
    using namespace std;
    cout << string("hello, i'm a string");
}

Что такое пространства имен и зачем они вам нужны, пожалуйста, прочитайте предложение, которое Бьярн Страуструп дал в 1993 году, чтобы добавить их в готовящийся стандарт C ++. Хорошо написано:

http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / документы / 1993 / N0262.pdf

27 голосов
/ 23 декабря 2008

В C++ понятия разные. Это по замыслу и полезно.

Вы можете включить вещи, которые без пространств имен были бы неоднозначными.

С помощью пространств имен вы можете ссылаться на два разных класса с одинаковыми именами. Конечно, в этом случае вы не будете использовать директиву using или, если вы это сделаете, вы должны будете указать пространство имен других элементов в требуемом пространстве имен.

Обратите внимание, что вам НЕ НУЖНО использовать - вы можете просто использовать std :: cout или все, что вам нужно для доступа. Вы вводите элементы в пространство имен.

9 голосов
/ 23 декабря 2008

В C ++ #include и использование имеют разные функции.

#include помещает текст включенного файла в ваш исходный файл (на самом деле единица перевода ), а пространства имен, с другой стороны, являются просто механизмом для получения уникальных имен, так что разные люди могут создавать " foo "object.

Это происходит из C ++, не имеющего понятия модуля.

Имейте в виду, что пространства имен в C ++ открыты, это означает, что разные файлы могут определять разные части одного и того же пространства имен (что-то вроде частичных классов .NET).

//a.h
namespace eg {
    void foo();
}

//b.h
namespace eg {
    void bar();
}
6 голосов
/ 23 декабря 2008

Включение определяет существование функций.

Использование облегчает их использование.

cout как определено в iostream, фактически называется "std :: cout".

Вы можете избежать использования пространства имен, написав.

std::cout << "Hello World";
4 голосов
/ 24 декабря 2008

Я думаю, что другие ответы немного упускают суть. Во всех C ++, Java и C #, using / import не является обязательным. Так что это не отличается.

А затем вам нужно сделать что-то еще, чтобы код был видимым на всех трех платформах.

В C ++ вам необходимо минимально включить его в текущий модуль перевода (достаточно для многих реализаций вектора, строки и т. Д.), Часто вам также необходимо добавить что-то в свой компоновщик, хотя некоторые библиотеки делают это автоматически на основе включения (например, повышение при сборке в Windows).

А в C # вы должны добавить ссылку на другую сборку. Это позаботится об эквиваленте включений и настроек ссылок.

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

Таким образом, на всех трех платформах требуются очень похожие вещи, и разделение между using / import (удобство) и фактическим разрешением связи (требование) одинаково во всех трех.

4 голосов
/ 23 декабря 2008

Эти ключевые слова используются для разных целей.

Ключевое слово using делает имя из пространства имен доступным для использования в текущем декларативном регионе. Это в основном для удобства, чтобы вам не приходилось постоянно использовать полное имя. Эта страница объясняет это в некоторых деталях.

Оператор #include является директивой препроцессора, и он указывает препроцессору обрабатывать содержимое указанного файла так, как если бы это содержимое появилось в исходной программе в момент появления директивы. То есть вы можете думать об этом заявлении как о копировании включенного файла в текущий. Затем компилятор компилирует весь файл так, как будто вы записали весь код в один большой файл.

3 голосов
/ 24 декабря 2008

Как указывалось, C ++ и Java - это разные языки, и они делают несколько разные вещи. Кроме того, C ++ больше похож на язык «изящного роста», а Java больше на язык разработки.

Хотя using namespace std; не обязательно является плохой идеей, использование его для всех пространств имен исключит всю выгоду. Пространства имен существуют для того, чтобы вы могли писать модули без учета конфликтов имен с другими модулями, а using namespace this; using namespace that; может создавать неоднозначности.

3 голосов
/ 23 декабря 2008

Вам нужно понять пространства имен , если вы действительно хотите это понять.

С include вы просто включаете заголовочный файл.

С using namespace вы заявляете, что используете заданное пространство имен, содержащее такие вещи, как cout. так что если вы сделаете это:

using namespace std;

вам использовать cout вы можете просто сделать

cout << "Namespaces are good Fun";

вместо:

std::cout << "Namespaces are Awesome";

Обратите внимание, что если вы не #include <iostream>, вы не сможете использовать ни std::cout, ни cout в своих декларациях и т. Д., Поскольку вы не включаете заголовок.

2 голосов
/ 25 мая 2016

В C ++ директива include скопирует и вставит файл заголовка в ваш исходный код на этапе предварительной обработки. Следует отметить, что заголовочный файл обычно содержит функции и классы, объявленные в пространстве имен. Например, заголовок <vector> может выглядеть примерно так:

namespace std {
    template <class T, class Allocator = allocator<T> > class vector;
    ...
} 

Предположим, вам нужно определить вектор в вашей главной функции, вы делаете #include <vector>, и теперь у вас есть фрагмент кода в вашем коде:

namespace std {
    template <class T, class Allocator = allocator<T> > class vector;
    ...
}
int main(){
   /*you want to use vector here*/
}

Обратите внимание, что в вашем коде векторный класс все еще находится в пространстве имен std. Однако ваша основная функция находится в пространстве имен global по умолчанию, поэтому простое включение заголовка не сделает класс вектора видимым в пространстве имен global. Вы должны либо использовать using, либо использовать префикс, например std::vector.

2 голосов
/ 24 декабря 2008

Один лайнер (не то чтобы это что-то новое :)):

с использованием std позволяет пропустить префикс std :: , но вы не можете использовать cout вообще без iostream .

...