(一)
先看一个简单的程序:
代码语言:javascript复制#include <iostream>
using namespace std;
int main()
{
int a = 1;
cout << a << endl;
}
运行结果:
代码语言:javascript复制1
这里的第一行,#include好理解,iostream是输入输出流,包含了输入流istream和输出流ostream。 第二行using namespace std; 这里的namespace是个关键字,表示它后面的std是一个命名空间。
什么是命名空间呢? 假定三年1班有一名小学生叫做寒上耕,三年2班也有一名小学生叫做寒上耕,四年3班也有一名小学生叫寒上耕,假如有个人说:我要找寒上耕。那么没人知道他要找哪位寒上耕。但是假如有个人说:我要找三年1班的寒上耕,大家就知道他要找的是认谁。 这里的三年1班,三年2班,四年3班,就是命名空间,作用是防止命名冲突。
那么程序里为何要使用命名空间std呢?不用行不行? 若把using namespace std;这行代码去掉,cout和endl会报错,程序不认识这两个词。
(二)
咱们看一个iostream中的代码(我用的编译器是CodeBlocks):
代码语言:javascript复制#ifndef _GLIBCXX_IOSTREAM
#define _GLIBCXX_IOSTREAM 1
#pragma GCC system_header
#include <bits/c config.h>
#include <ostream>
#include <istream>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
* @name Standard Stream Objects
*
* The <iostream> header declares the eight <em>standard stream
* objects</em>. For other declarations, see
* http://gcc.gnu.org/onlinedocs/libstdc /manual/io.html
* and the @link iosfwd I/O forward declarations @endlink
*
* They are required by default to cooperate with the global C
* library's @c FILE streams, and to be available during program
* startup and termination. For more information, see the section of the
* manual linked to above.
*/
//@{
extern istream cin; /// Linked to standard input
extern ostream cout; /// Linked to standard output
extern ostream cerr; /// Linked to standard error (unbuffered)
extern ostream clog; /// Linked to standard error (buffered)
#ifdef _GLIBCXX_USE_WCHAR_T
extern wistream wcin; /// Linked to standard input
extern wostream wcout; /// Linked to standard output
extern wostream wcerr; /// Linked to standard error (unbuffered)
extern wostream wclog; /// Linked to standard error (buffered)
#endif
//@}
// For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif /* _GLIBCXX_IOSTREAM */
咱们看到了在iosteam中,cin(输入),cout(输出),cerr(错误),clog(日志)都是在std里定义的。
代码语言:javascript复制若你用的是Mac系统的Xcode编译器,则iostream头文件中的内容如下所示:
C -*-
//===--------------------------- iostream ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_IOSTREAM
#define _LIBCPP_IOSTREAM
/*
iostream synopsis
#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>
namespace std {
extern istream cin;
extern ostream cout;
extern ostream cerr;
extern ostream clog;
extern wistream wcin;
extern wostream wcout;
extern wostream wcerr;
extern wostream wclog;
} // std
*/
#include <__config>
#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_HAS_NO_STDIN
extern _LIBCPP_FUNC_VIS istream cin;
extern _LIBCPP_FUNC_VIS wistream wcin;
#endif
#ifndef _LIBCPP_HAS_NO_STDOUT
extern _LIBCPP_FUNC_VIS ostream cout;
extern _LIBCPP_FUNC_VIS wostream wcout;
#endif
extern _LIBCPP_FUNC_VIS ostream cerr;
extern _LIBCPP_FUNC_VIS wostream wcerr;
extern _LIBCPP_FUNC_VIS ostream clog;
extern _LIBCPP_FUNC_VIS wostream wclog;
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_IOSTREAM
可以看到,CodeBlocks和Xcode关于iostream的内容,有不小的差异。但是一些关于C 的标准,还是一致的。
(三)
那么endl是在哪里定义的呢? 咱们看一下定义endl的源码,具体是定义在ostream里面
代码语言:javascript复制#ifndef _GLIBCXX_OSTREAM
#define _GLIBCXX_OSTREAM 1
#pragma GCC system_header
#include <ios>
#include <bits/ostream_insert.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
......
......
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('n'))); }
......
......
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#include <bits/ostream.tcc>
#endif /* _GLIBCXX_OSTREAM */
可以看到,endl是定义在ostream中的std中。 因为iostream头文件已经包含了ostream头文件和istream头文件,所以咱们的代码中只需要包含iostream头文件即可。
另一方面,咱们注意到,在iostream头文件和ostream头文件中都包含了命名空间std。可见命名空间可以散布到不同的头文件。事实上,std不止在这两个头文件中有,在其他的头文件中也有,作用是把一些常用的操作符都包含进来。然后在你写的代码中引入using namespace std;后,即可减少命名冲突。
(四)
假如咱们不写using namepace std;那么在使用相关的操作符时,需要加上std
代码语言:javascript复制#include <iostream>
int main()
{
int a = 1;
std::cout << a << std::endl;
}
再看一个例子
代码语言:javascript复制#include <iostream>
namespace A
{
int x = 10;
};
namespace B
{
int x = 20;
};
using namespace B;
int main()
{
std::cout << x << std::endl;
}
这个程序里,有两个命名空间A和B,都定义了变量x。因为已经说明了using namespace B; 所以打印出20。
(五)
若没说明使用哪个命名空间,必须在x前面指明命名空间,否则编译会报错。
代码语言:javascript复制#include <iostream>
namespace A
{
int x = 10;
};
namespace B
{
int x = 20;
};
int main()
{
std::cout << B::x << std::endl;
std::cout << A::x << std::endl;
}
运行结果:
代码语言:javascript复制20
10