C++ 自己实现cout

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


接触这么久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();

扯了这么多,其实这里面表达的意思是:为了解决名字冲突问题,引入了名字空间这个概念,通过使用 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++的这些特性,当我们学得深入了以后,就很有必要弄懂了。

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页