小朋友学C++(21):命名空间

(一)

先看一个简单的程序:

#include <iostream>
using namespace std;

int main()
{
    int a = 1;
    cout << a << endl;
}

运行结果:

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):

#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 &lt;iostream&gt; 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里定义的。

若你用的是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里面

#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

#include <iostream>

int main()
{
    int a = 1;
    std::cout << a << std::endl;
}

再看一个例子

#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前面指明命名空间,否则编译会报错。

#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;
}

运行结果:

20
10


TopCoder & Codeforces & AtCoder交流QQ群:648202993
更多内容请关注微信公众号
wechat_public_header.jpg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值