如果你已经看过我关于运算符重载的文章,并且已经理解;那么我们就可以轻而易举的实现出自己的cout和endl
当然,不会实现出std::cout那么强悍的功能. 毕竟这可是要从底层开始写起来的,博主这种三键程序员还是算了,但是只是实现出一个类似的,帮助你进一步对运算符重载的理解还是没问题的
整个项目源码,下载地址在最下方
上代码
#include < cstdio >
#pragma once
namespace bbxyIO
{
struct ENDL;
class Stream
{
public:
// 为了方便,就使用printf实现cout的功能了,但是要注意,cout和printf虽然底层原理是相同的,但是实现思路和过程以及功能都是不一样的
// 类内重载运算符,会比类外重载运算符更省事.
// 类成员函数具有隐藏参数 this 指针
// (除静态类成员函数,因为static本质上还是全局函数,只不过名义上的划分给类罢了,所以你可以通过类名直接调用)
Stream& operator<<(char character)
{
printf("%c", character);
return *this; // 不要直接return this因为返回值是Stream& 会返回一个一级指针,你需要在类对象地址前面加*号,对其进行降级操作
}
Stream& operator<<(const char* string)
{
printf("%s", string);
return *this;
}
Stream& operator<<(short number)
{
printf("%d", number);
return *this;
}
Stream& operator<<(int number)
{
printf("%d", number);
return *this;
}
Stream& operator<<(long number)
{
printf("%d", number);
return *this;
}
Stream& operator<<(float number)
{
printf("%f", number);
return *this;
}
Stream& operator<<( ENDL& e) // 不要想着用typedef来修改这个ENDL类型,因为底层的类型就那么多,别名再多也不过是针对程序员的
{
printf("/r/n");
return *this;
}
};
inline Stream cout{};
struct ENDL {}endl;// 为了实现类似于std命名空间作用域下的endl,需要定义一个新类型出来,好进行重载运算符
//
// 这个就是类外重载运算符的例子,双目运算符重载你需要给它两个参数,类内声明双目运算符重载,则可以免去参数1,因为this指针会以隐藏参数传进来
inline Stream& operator<<(Stream&cout, double number)
{
printf("%e", number);
return cout;
}
}
这样一个我们自己的cout和endl就实现出来了
我们现在就可以去main函数里面体验自己的cout了
#include "myIO.hpp"
#include < iostream >
int main(int,char**,char**)
{
// 成员名相同,所以应该使用命名空间划分作用域
int var1 = 14;
bbxyIO::cout << 'a' << '\n'<< '\a'<< 'b' << "我是字符串\t";
bbxyIO::cout << 1+1 << 6+var1 << ++var1 << 1.6f;
bbxyIO::cout << 1.0 << bbxyIO::endl;
bbxyIO::cout.operator<<(1).operator<<(2); // operator运算符重载,就是函数,只不过可以更方便的简化使用
bbxyIO::cout << 1 << 2;
// 上面这两行代码是等价的
std::cout << 'a' << '\n' << '\a' << 'b' << "我是字符串\t";
std::cout << 1 + 1 << 6 + var1 << ++var1 << 1.6f;
std::cout << 1.0 << std::endl;
std::cout.operator<<(1).operator<<(2); // operator运算符重载,就是函数,只不过可以更方便的简化使用
std::cout << 1 << 2;
// 上面这两行代码是等价的
return 0;
}
运行的非常成功,你可以根据自己的需求,写出属于自己项目的cout了
不要在两个函数名相同的情况下使用using namespace xxx;
你会让编译器搞不清应该用哪个函数.
找到StringStream就是本章代码