Подтвердить что ты не робот

С++ и включить

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

Например,

#include <iostream>

using namespace std;

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

использование директив и включение директив препроцессора - это две разные вещи. 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, где вы только делаете имена видимыми для пакета, появляется строка импорта, в С++ она может влиять на всю программу, если они включают этот файл прямо или косвенно.

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

#include <string>
#include <iostream>

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

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

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1993/N0262.pdf

Ответ 3

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

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

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

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

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

//b.h
namespace eg {
    void bar();
}

Ответ 4

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

Использование упрощает их использование.

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

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

std::cout << "Hello World";

Ответ 5

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

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

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

Ответ 6

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

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

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

И в С# вам нужно добавить ссылку на другую сборку. Это касается эквивалентных включений и настроек ссылок.

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

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

Ответ 7

Вам нужно понять namespaces, если вы хотите по-настоящему понять это.

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

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

using namespace std;

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

cout << "Namespaces are good Fun";

вместо:

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

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

Ответ 8

Как указано, С++ и Java - это разные языки и делают несколько разные вещи. Кроме того, С++ - это скорее язык "jest grow", а Java - более разработанный язык.

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

Ответ 9

Даже Stroustrup ссылается на механизм #include как несколько хакерский. Однако это упрощает раздельную компиляцию (компилировать скомпилированные библиотеки и заголовки вместо всего исходного кода).

Вопрос в том, "почему С++ - после того, как у него уже был механизм #include - добавить пространства имен?"

Лучший пример, о котором я знаю, о том, почему #include недостаточно, поступает от Sun. По-видимому, разработчики Sun столкнулись с некоторыми проблемами с одним из своих продуктов, потому что они написали функцию mktemp(), которая имела ту же подпись, что и функция mktemp(), которая была включена через файл, который сам был включен через заголовок, на самом деле проект хотел.

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

Проблема связана с тем, что С++ был первоначально совместим с - и, по существу, с копией поверх - C. И C имеет только глобальное пространство имен. С++ решил эту проблему - в коде, который несовместим с C - через пространства имен.

Оба С# и Java (1) имеют механизм пространства имен (namespace в С#, package в Java), (2) обычно разрабатываются через IDE, которые обрабатывают обращение к двоичным файлам для разработчика, и (3) "Разрешить автономные функции (область видимости класса является чем-то вроде пространства имен и снижает риск загрязнения глобального пространства имен), поэтому у них есть другое решение этой проблемы. Тем не менее, по-прежнему возможно иметь некоторую двусмысленность в отношении того, какой метод вы вызываете (скажем, столкновение имен между двумя интерфейсами, которым наследуется класс), и в этом случае всем трем языкам требуется, чтобы программист четко указывал, какой метод они используют на самом деле ищет, обычно, добавляя родительский класс/имя интерфейса.

Ответ 10

Один вкладыш (не то, что это что-то новое:)):

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

Ответ 11

В С++ директива 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.