你好,我是悦创。


前排提示:阅读本篇文章需要至少学过类和对象以及重载运算符的概念。


接触这么久 C++ 了,我想尝试写一个自己的 cout 了。在实现之前,先扯扯几个概念:

一、cout 是谁?

不就是输出语句嘛?!这个答案太浅显。

正确答案: cout 是类 ostream 的一个对象,而这个对象有一个成员重载运算符函数:​​operator <<​​。顺便一说,类 ostream 又属于 iostream 库中,iostream 是标准的 C++ 头文件。既然如此,那么这个头文件里应该是这样写的:

//iostream
class ostream
{
public:
ostream operator << (int n){输出n}
ostream operator << (double n){输出n}
...
}
ostream cout;

这个 ​​ostream::operator <<​​​ 有多个重载版本,所以形参什么类型都有,包括 int,double,char 等等。当我们写 ​​cout<<a​​​ 时,其实也可以写成 ​​cout.operator<<(a)​​ 。

cout 的语句格式是:​​cout<<表达式1<<表达式2<<……<<表达式n;​​​ ,那么如果按照以上的写法,我们只能写诸如 ​​cout<<a;​​​ 的语句,而不能写成 ​​cout<<a<<b<<c;​​ 这样连起来的形式,可是 C++ 里面却能实现这样的写法,这是为什么呢?

原来在 ​​ostream::operator <<​​​ 里还有一句 ​​return *this​​​ 。当执行语句 ​​cout<<a<<b<<c;​​​ 时,先执行 ​​cout.operator<<(a)​​​ ,然后这个函数会返回 cout,其实就是返回自己本身,然后再去执行 ​​cout.operator<<(b)​​ ,然后又会去执行下一个函数,以此类推。

因此可以这样实现:

ostream &operator << (int n)
{
输出n;
return *this;
}

二、什么是namespace?

我们经常在程序开头写 ​​using namespace std;​​ ,但有没有想过是干什么用的?

顾名思义,namespace 的意思是 命名空间,它是用来组织和重用代码的。那这个到底有什么用呢?

好,我们在脑中想这么一种情况:你写了一个库文件,里面有个名字叫 fun 的函数,很不幸你另外一个人写的库文件也有个名字叫 fun 的函数,这样就冲突了。

//你的库文件里:
void fun();

//别人的库文件里:
void fun();

//有人想用fun()
fun(); //究竟该用哪个?冲突了!

这时,我们就想了一个办法:


  • 把你写的 fun 函数放到一个你命名的空间里,把另外一个人写的 fun 函数放到另一个命名空间里。
  • 只要有人说要用你的空间,那么他用的 fun 函数肯定是你写的 fun 函数,不会是另外一个人的。
  • 如果那个人说要用另一个人的空间,那么他用的 fun 函数肯定是另一个人写的 fun 函数,不会是你的。

//你的库文件里:
namespace you{void fun();}

//别人的库文件里:
namespace other{void fun();}

//当有人用你的函数时:
you::fun();

//当有人用另外一个人的函数时:
other::fun();

//如果有人说要用你的空间,像这样:
using namespace you;
fun();//这个其实是you::fun();,不会是other::fun();


如果,你直接使用 cout 而不使用 namespace ,那系统不知道你在用的是谁的 cout (没准有多个 cout 呢?)


扯了这么多,其实这里面表达的意思是:为了解决名字冲突问题,引入了名字空间这个概念,通过使用 ​​namespace xxx;​​ 你所使用的库函数或变量就是在该名字空间中定义的,这样一来就不会引起不必要的冲突了。

那我们为什么要写 ​​using namespace std;​​​ ?早期的 C 将标准库功能定义在全局空间里,声明在带 ​​.h​​ 后缀的头文件里。


  • C++ 标准为了和 C 区别开,也为了正确使用命名空间,规定头文件不使用后缀 ​​.h​​ 。因此,当使用 ​​<iostream.h>​​ 时,相当于在 C 中调用库函数,使用的是全局命名空间,这也是早期的 C++ 实现;
  • 当使用 ​​<iostream>​​ 的时候,该头文件没有定义全局命名空间,必须使用 ​​namespace std;​​ 这样才能正确使用 cout。

假如不写 ​​using namespace std;​​​,那就要写成 ​​std::cout<<​​ 了。每一句都这么写很烦,于是干脆在程序开头直接来一句 ​​using namespace std;​​。

好了,其实这个 iostream 库大概是这么写的:

//iostream
namespace std{
class ostream
{
public:
ostream operator << (int n){输出n}
ostream operator << (double n){输出n}
...
}
}
std::ostream cout;

三、自己实现 cout

以上两个已经讲得很清楚了,下面上实现 cout 的代码:

#include<stdio.h>

namespace Mystd{ //命名空间
class MyOstream{
public:
const MyOstream& operator<<(const int integer) const
{
printf("%d", integer);
return *this;
}
const MyOstream& operator<<(const char *s) const
{
printf("%s", s);
return *this;
}
};
}

void Print()
{
Mystd::MyOstream MyAnothercout;
MyAnothercout<<"Print";
}

int main()
{
Mystd::MyOstream Mycout;
int a = 30, b = 20;
Mycout<<"number:"<<a<<" "<<b<<"\n";
Print();
return 0;
}

本代码已经通过编译,并且能正确输出。对于C++的这些特性,当我们学得深入了以后,就很有必要弄懂了。


C++ 自己实现cout和为什么使用 using namespace std;_c++