5

喜欢 :

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

事实上,这是一个受此问题下评论启发的问题:

.h 什么时候不需要包含头文件?

4

5 回答 5

8

这称为使用声明。实际上有两种方法可以使用using关键字。在类定义中使用了第三种特殊形式的 using 声明,但这里我将重点关注一般的 using 声明。(见下文)。

  • 使用声明
  • 使用指令

它们有两种截然不同的效果。using声明将名称声明为另一个声明或一组声明的别名(如果您要命名一组重载函数)。该名称是在当前范围内声明的。也就是说,您也可以在块内使用它

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

如果您经常在本地使用名称并且您不想在所有使用中添加前缀,这将非常有用,并且在使用依赖于参数的查找习惯用法实现交换时也很有用。

using指令命名命名空间并且不声明任何名称。相反,它将修改名称查找以查找未在其认为的位置真正声明的名称。对于非限定名称查找,它查找在包含 using 指令和目标名称空间的封闭名称空间中声明的名称。将找到在目标命名空间中声明的所有名称:

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

在这里,cout将被认为在全局命名空间中被声明了两次,并导致了歧义(::同时包含了mainand std)。在限定名称查找中,它将使用 using 指令中命名的所有名称空间构建名称空间的传递闭包。

using namespace foo;

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

c不仅在全局命名空间中查找,而且在命名空间foofoo具有 using 指令的命名空间中查找等等。但是,如果全局命名空间包含直接声明(包括 using 声明),则该声明将隐藏通过 using 指令间接找到的声明:

using namespace foo;
int c;

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

using 声明可以出现在很多地方,包括在类定义中。它的含义与其他地方的含义相似,但有一个重要限制:它将名称声明为一个或多个声明的别名,但声明必须是基类的成员。这对于使派生类中的名称可见非常有用,否则该派生类将被在那里声明的相同名称隐藏

struct base {
  void f();
};

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

现在您可以调用d.f(). 如果没有 using 声明,则名称查找只会找到fin 的一个声明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()本例中)设置别名,那么显式声明仍将隐藏使用声明为其别名的函数声明 - 因此两个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()

于 2010-03-28T11:09:44.197 回答
7

不幸的是,您正在查看的示例晦涩难懂。

using ::_Filet;

正如其他人所指出的,该using声明使来自指定命名空间的名称在当前命名空间中可用。在该文件中似乎没有打开命名空间,因此您假设当前命名空间是全局命名空间,并且::在它寻址全局命名空间之前也没有任何内容。所以在这里我们似乎将一个名称从全局命名空间移动到全局命名空间。那是怎么回事?

答案是使用宏:

_STD_BEGIN

这被定义为namespace std {。因此,using声明所做的是使这些名称出现在std命名空间中,否则它们只会出现在全局命名空间中。

于 2010-03-28T10:52:25.883 回答
3

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++ 程序员使用它们。

于 2010-03-28T10:39:29.560 回答
3

'using' 关键字允许您将名称从命名空间带入当前命名空间。如果您想在命名空间中使用名称而不将它们带入当前命名空间,则必须使用<namespace name>::<name>格式,如下所示:


std::cout << "Hello World";

如果cout被带入当前命名空间,那么您可以像下面这样使用它:


cout << "Hello World";

using关键字可以通过以下方式使用:

  • 作为 using 指令 ​​( using namespace <namespace name>;):

using namespace std;

这会将std命名空间内的所有名称都带入当前命名空间。

  • 作为使用声明 ( using <namespace>::<member name>;):

using std::cout;

这只会将std::cout名称带入当前命名空间。

于 2010-03-28T10:44:33.893 回答
0

using使来自指定命名空间的名称在当前命名空间中可用。

于 2010-03-28T12:06:52.710 回答