Что означает использование в C ++? - PullRequest
5 голосов
/ 28 марта 2010

Как:

using ::size_t; using ::fpos_t; using ::FILE;

На самом деле это вопрос, вдохновленный комментарием к этому вопросу:

Когда .h не требуется включать заголовочный файл?

Ответы [ 5 ]

7 голосов
/ 28 марта 2010

К сожалению, пример, который вы смотрите, неясен.

using ::_Filet;

Как уже отмечали другие, объявление using делает имя из указанного пространства имен доступным в текущем пространстве имен. В этом файле, по-видимому, нет открытых пространств имен, поэтому можно предположить, что текущее пространство имен является глобальным пространством имен, а также ::, и ничего не будет, прежде чем оно коснется глобального пространства имен. Итак, здесь мы, кажется, перемещаем имя из глобального пространства имен в глобальное пространство имен. Что с этим?

Ответ заключается в использовании макроса:

_STD_BEGIN

Это определяется как namespace std {. Поэтому объявления using делают так, чтобы эти имена появлялись в пространстве имен std, в противном случае они были бы только в глобальном пространстве имен.

6 голосов
/ 28 марта 2010

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

  • с использованием декларации
  • с использованием директивы

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

int main() {
  using std::swap;
  // ...
}

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

A с использованием директивы присваивает имена пространству имен и не объявляет никаких имен. Вместо этого он изменит поиск имен, чтобы найти имена, которые на самом деле не объявлены там, где, по его мнению, они находятся. Для неквалифицированного поиска имени он находит имена, объявленные во включающем пространстве имен, которое охватывает как директиву using, так и целевое пространство имен. Будут найдены все имена, которые объявлены в целевых пространствах имен:

int cout;
int main() {
  using namespace std;
  // cout << 1; ambiguous!
}

Здесь cout будет считаться дважды объявленным в глобальном пространстве имен и вызывает неоднозначность (:: включает в себя как main, так и std). В квалифицированном namelookup он будет создавать транзитивное закрытие пространства имен со всеми пространствами имен, указанными в директивах using.

using namespace foo;

int main() {
  ::c++; 
}

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

using namespace foo;
int c;

int main() {
  ::c++; // not ambiguous!
}

Использование объявлений может появляться во многих местах, в том числе внутри определений классов. Его значение аналогично его значению в другом месте с важным ограничением: оно объявляет имя как псевдоним одного или нескольких объявлений, но объявления должны быть членами базового класса. Это очень полезно для отображения имен в производном классе, которые в противном случае были бы скрыты под тем же именем, объявленным там

struct base {
  void f();
};

struct derived : base {
  using base::f; // name "f" declared in derived
  void f(int); // overloads the using declaration
};

Теперь вы можете позвонить d.f(). Если бы не было никакого объявления об использовании, тогда поиск имени нашел бы только одно объявление f в derived и остановил бы поиск, не углубляясь в область действия базового класса:

derived d;
d.f(); // invalid without the using declaration
d.f(0); // valid with or without the using declaration

// explicitly starting lookup in base: valid with or without the using declaration
d.base::f();

Это также позволяет изменить доступность членов базового класса, хотя вы должны использовать это экономно:)

На практике мне показалось полезным сделать виртуальную функцию-член повторно видимой:

struct base {
  virtual void f();
  virtual void f(int);
};

struct derived : base {
  // using base::f; would solve it
  virtual void f() { ... }
};

Упс - теперь d.f(0); недопустим, потому что поиск имени находит только нулевой параметр f! Директива using решит эту проблему. Обратите внимание, что если вы создаете псевдоним объявления функции, который имеет те же типы параметров и константу, что и явное объявление (например, f() в этом случае), то явное объявление все равно будет скрывать то, для которого объявление using является псевдонимом - так что оба f() функции не будут конфликтовать в этом случае.

Альтернативой для решения этой проблемы является использование идиома не виртуального интерфейса

struct base {
  void f() { do_f(); }
  void f(int) { do_f(0); }

private:
  virtual void do_f();
  virtual void do_f(int);
};

struct derived : base {
private:
  virtual void do_f() { ... }
};

struct derived1 : derived {
private:
  virtual void do_f(int) { ... }
};

Теперь и d.f(0), и d.f() действительны независимо от того, какой объект вы называете.

3 голосов
/ 28 марта 2010

Ключевое слово using позволяет вам переносить имена из пространства имен в текущее пространство имен. Если вы хотите использовать имя внутри пространства имен без переноса их в текущее пространство имен, вам придется использовать формат <namespace name>::<name>, как показано ниже:


std::cout &lt&lt "Hello World";

Если cout заносится в текущее пространство имен, вы можете использовать его, как показано ниже:


cout &lt&lt "Hello World";

Ключевое слово using можно использовать следующими способами:

  • В качестве директивы использования (using namespace <namespace name>;):

using namespace std;

Приносит все имена из пространства имен std в текущее пространство имен.

  • В качестве декларации использования (using <namespace>::<member name>;):

using std::cout;

Это приносит только имя std::cout в текущее пространство имен.

3 голосов
/ 28 марта 2010

using <some symbol> вытянуть символ из его пространства имен в текущее пространство имен. Предположим, следующий код:

namespace foo {
  // Assume you want to use std::string, you can either do
  std::string bar;
  // or
  using std::string;
  string bar;
}

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

Пространство имен :: является особым случаем, поскольку оно относится к глобальному пространству имен; в данном конкретном случае функции, на которые вы ссылаетесь, являются функциями C, а C не знает о пространствах имен C ++, поэтому они попадают в глобальное пространство имен.

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

0 голосов
/ 28 марта 2010

using делает имя из указанного пространства имен доступным в текущем пространстве имен.

...