C ++命名空间和include

时间:2008-12-23 20:04:20

标签: c++ namespaces header-files

为什么我们需要在C ++程序中使用namespace和include指令?

例如,

#include <iostream>

using namespace std;

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

为什么只有#include或只是使用“使用命名空间std”是不够的 并摆脱对方?

(我想到与Java类比,导入java.net。*将导入导入所有内容 从java.net,你不需要做任何其他事情。)

11 个答案:

答案 0 :(得分:39)

使用指令和包含预处理器指令是两回事。 include大致对应于Java的CLASSPATH环境变量,或java虚拟机的-cp选项。

它的作用是使编译器知道类型。例如,仅包含<string>将使您能够引用std::string

#include <string>
#include <iostream>

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

现在,使用指令与Java中的import类似。它们使名称在它们出现的范围内可见,因此您不必再完全限定它们。与在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不同,在Java中只显示包的名称,导入行出现在C ++中,如果它们直接或间接包含该文件,它可以影响整个程序。

在全局范围内进行操作时要小心,即使在实现文件中也是如此。最好尽可能使用它们。对于namespace std,我从不使用它。我和许多其他人一样,总是在名字前面写std::。但如果你碰巧这样做,那就这样做:

#include <string>
#include <iostream>

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

对于什么名称空间以及为什么需要它们,请阅读Bjarne Stroustrup给出的提议,将它们添加到即将推出的C ++标准中。写得很好:

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

答案 1 :(得分:27)

C++中,概念是分开的。这是设计和有用的。

您可以包含没有名称空间的内容。

使用命名空间,您可以引用具有相同名称的两个不同的类。当然,在这种情况下,您不会使用using指令,或者如果您这样做,则必须在您想要的命名空间中指定其他内容的命名空间。

另请注意,您不需要使用 - 您可以使用std :: cout或您需要访问的任何内容。您在项目前加上命名空间。

答案 2 :(得分:9)

在C ++ #include中使用具有不同的功能。

#include将包含文件的文本放入源文件(实际上是translation unit),另一方面,名称空间只是一种具有唯一名称的机制,以便不同的人可以创建“foo” “对象。

这来自C ++没有模块的概念。

请记住,C ++中的命名空间是开放的,这意味着不同的文件可以定义同一命名空间的不同部分(有点像.NET的部分类)。

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

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

答案 3 :(得分:6)

include包含了函数的存在。

使用更容易使用它们。

iostream中定义的

cout实际上命名为“std :: cout”。

您可以通过编写来避免使用命名空间。

std::cout << "Hello World";

答案 4 :(得分:4)

这些关键字用于不同目的。

using关键字从可用于当前声明性区域的命名空间中创建名称。它主要是为了方便您不必一直使用完全限定名称。这个page详细解释了它。

#include语句是一个预处理器指令,它告诉预处理器处理指定文件的内容,就好像这些内容出现在源程序出现的那一点。也就是说,您可以将此语句视为将包含的文件复制到当前文件中。然后,编译器将编译整个文件,就像您在一个大文件中编写了所有代码一样。

答案 5 :(得分:4)

我认为其他答案略微缺少这一点。在所有C ++,Java和C#中,using / import事物完全是可选的。所以这并没有什么不同。

然后你必须做其他事情才能使代码在所有三个平台上都可见。

在C ++中,你最低限度地必须将它包含在当前的转换单元中(对于vector,string等的许多实现来说已经足够了),通常你也需要向链接器中添加一些内容,尽管有些库会自动执行此操作。基于include(例如在Windows上构建时的提升)。

在C#中,您必须添加对其他程序集的引用。这需要相当于包含和链接设置。

在Java中,你必须确保代码在类路径上,例如添加相关的jar。

因此,在所有三个平台上都需要非常类似的东西,using / import(便利)与实际链接解决方案(要求)之间的分离在所有三个平台上是相同的。

答案 6 :(得分:3)

如果您想真正了解这一点,则需要了解namespaces

使用include,您只需要包含头文件。

使用using namespace,您声明您正在使用包含诸如cout等内容的给定命名空间。所以如果你这样做:

using namespace std;

你可以使用cout

cout << "Namespaces are good Fun";

而不是:

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

请注意,如果您没有#include <iostream>,则无法在声明中同时使用std::coutcout等等,因为您未包含标题。< / p>

答案 7 :(得分:3)

正如所指出的,C ++和Java是不同的语言,并且做了一些不同的事情。此外,C ++更像是一种“开玩笑”的语言,而Java更像是一种设计语言。

虽然using namespace std;不一定是个坏主意,但将它用于所有名称空间将消除整个好处。存在命名空间,以便您可以编写模块而不考虑与其他模块的名称冲突,using namespace this; using namespace that;可能会产生歧义。

答案 8 :(得分:2)

即使Stroustrup将#include机制称为有点hackish。但它确实使单独编译变得更容易(发送编译的库和头文件而不是所有源代码)。

问题实际上是“为什么C ++ - 在它已经有#include机制之后 - 添加命名空间?”

我知道#include为什么不够的最好的例子来自Sun.显然,Sun开发人员在使用其中一个产品时遇到了一些问题,因为他们编写了一个mktemp()函数,该函数碰巧具有与mktemp()函数相同的签名,该函数包含在一个文件中,该文件本身包含在项目实际上想要的标题。

当然这两个功能不兼容,一个不能用作另一个的替代品。另一方面,编译器和链接器在构建二进制文件时没有意识到这一点,有时mktemp()会调用一个函数,有时它会根据编译或链接的不同文件的顺序调用另一个函数。

问题源于这样一个事实:C ++最初与C兼容 - 并且基本上是在C之上.C和C只有一个全局命名空间。 C ++通过命名空间解决了这个问题 - 在与C不兼容的代码中。

C#和Java(1)都有一个命名空间机制(C#中为namespace,Java中为package),(2)通常是通过处理开发人员引用二进制文件的IDE开发的, (3)不允许独立函数(类范围是命名空间,并降低污染全局命名空间的风险),因此他们对此问题有不同的解决方案。但是,对于您调用的方法(例如,类继承的两个接口之间的名称冲突)仍然存在一些歧义,在这种情况下,所有三种语言都需要程序员明确指定它们是哪种方法实际上是寻找,通常是通过预先设置父类/接口名称。

答案 9 :(得分:2)

一个班轮(不是这是新的东西:)):

使用std 允许您省略 std :: 前缀,但如果没有 iostream cout >

答案 10 :(得分:2)

在C ++中,include指令会在预处理步骤中将头文件复制并粘贴到源代码中。应该注意,头文件通常包含在命名空间内声明的函数和类。例如,<vector>标题可能类似于以下内容:

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

假设您需要在main函数中定义一个向量,您执行#include <vector>并且您现在在代码中拥有上面的代码:

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

请注意,在您的代码中,vector类仍位于std命名空间中。但是,您的main函数位于默认的global命名空间中,因此只包含标题不会使global命名空间中的矢量类可见。您必须使用using或做std::vector前缀。