持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
对于C++的朋友,相信对于
std::cin和std::cout一定不陌生
那么,它们的内部实现是怎么样的呢?
为什么std::cin不用去指定我们的读入类型呢?
为什么std::cout不用去指定我们的输出类型呢?
本文中,关注的是对流的处理部分,至于对于流本身,并不讨论,所以,我们的流采取字符数组的形式 ( 设计一个缓冲区不是本文的讨论范围
模板特化
不要觉得模板只是个屠龙技!
template <typename T> void fun(T x);
template <> void fun(int x) { std::cout << "int" << std::endl; }
template <> void fun(float x) { std::cout << "float" << std::endl; }
template <> void fun(double x) { std::cout << "double" << std::endl; }
特化是一个很好用的特性,我们可以根据特化,来衍生出不一样的行为
有什么用呢?
我们可以利用特化和类的指定特化类型,来达到识别对象的类型(当然,有弊端,必须我们实现类型特化的代码)
比如:
#include <bits/stdc++.h>
template <typename Type> struct type {
friend std::ostream &operator<<(std::ostream &os, type);
};
std::ostream &operator<<(std::ostream &os, type<int>) {
return os << "int";
}
std::ostream &operator<<(std::ostream &os, type<float>) {
return os << "float";
}
std::ostream &operator<<(std::ostream &os, type<double>) {
return os << "double";
}
int main() {
std::cout << type<int>() << type<float>() << type<double>() << std::endl;
return 0;
}
上述代码我们就可以直接输出 int,float,double的字符串值
可能看到这里你会发现,这个好像也没什么用。
接下来,我们就试试写一个 cin 出来
cin 的实现
cin 的定义
其实,为了通用,它是一个 istream 对象
我实现时就不考虑泛化和接口了,直接粗暴的实现我们的 cin
class istream {
FILE *steam_;
public:
explicit istream(FILE *steam = stdin) : steam_(steam){};
istream &operator>>(int &t) {
fscanf(steam_, "%d", &t);
return *this;
}
istream &operator>>(float &t) {
fscanf(steam_, "%f", &t);
return *this;
}
istream &operator>>(double &t) {
fscanf(steam_, "%lf", &t);
return *this;
}
istream &operator>>(char &t) {
fscanf(steam_, "%c", &t);
return *this;
}
istream &operator>>(char t[]) {
fscanf(steam_, "%s", t);
return *this;
}
};
istream cin;
我们可以利用fscanf来帮助我们出来这些东西(流的出来和字符串转换不是我们的重点)
那么,如何自定义类型输出呢?
只要我们有函数定义,我们不就调用operator<<(istream &in, pack &cur)么!
struct pack {
int a;
int b;
friend istream &operator>>(istream &in, pack &cur);
};
istream &operator>>(istream &in, pack &cur) {
in >> cur.a;
in >> cur.b;
return in;
}
道理很简单,有函数定义就找得到就ok
至于pack里面的 friend 关键字,其实讲道理,这个关键字可以不加
( 只要你不访问内部成员
好了!
我们现在基本上实现了一个裸的cin,但是不能够过滤空白字符!
比起真正的cin还是逊色非常多
下面,我们来看看cout的实现
cout 的实现
class ostream {
FILE *steam_;
public:
explicit ostream(FILE *steam = stdout) : steam_(steam){};
friend void endl(ostream &os);
friend void end(ostream &os);
ostream &operator<<(int &t) {
fprintf(steam_, "%d", t);
return *this;
}
ostream &operator<<(float &t) {
fprintf(steam_, "%f", t);
return *this;
}
ostream &operator<<(double &t) {
fprintf(steam_, "%lf", t);
return *this;
}
ostream &operator<<(char &t) {
fprintf(steam_, "%c", t);
return *this;
}
ostream &operator<<(const char t[]) {
fprintf(steam_, "%s", t);
return *this;
}
ostream &operator<<(void (*cur)(ostream &)) {
cur(*this);
return *this;
}
};
void endl(ostream &os) {
putc('\n', os.steam_);
fflush(os.steam_);
}
void end(ostream &os) { fflush(os.steam_); }
和 cin一样的实现,但是我们多了一点函数用于清空缓冲区!
endl 代表着要换行
end 代表着不换行
但两者都要刷新缓冲区
下面我们来看看如何使用这两个
使用
#include <bits/stdc++.h>
class istream {
FILE *steam_;
public:
explicit istream(FILE *steam = stdin) : steam_(steam){};
istream &operator>>(int &t) {
fscanf(steam_, "%d", &t);
return *this;
}
istream &operator>>(float &t) {
fscanf(steam_, "%f", &t);
return *this;
}
istream &operator>>(double &t) {
fscanf(steam_, "%lf", &t);
return *this;
}
istream &operator>>(char &t) {
fscanf(steam_, "%c", &t);
return *this;
}
istream &operator>>(char t[]) {
fscanf(steam_, "%s", t);
return *this;
}
};
class ostream {
FILE *steam_;
public:
explicit ostream(FILE *steam = stdout) : steam_(steam){};
friend void endl(ostream &os);
friend void end(ostream &os);
ostream &operator<<(int &t) {
fprintf(steam_, "%d", t);
return *this;
}
ostream &operator<<(float &t) {
fprintf(steam_, "%f", t);
return *this;
}
ostream &operator<<(double &t) {
fprintf(steam_, "%lf", t);
return *this;
}
ostream &operator<<(char &t) {
fprintf(steam_, "%c", t);
return *this;
}
ostream &operator<<(const char t[]) {
fprintf(steam_, "%s", t);
return *this;
}
ostream &operator<<(void (*cur)(ostream &)) {
cur(*this);
return *this;
}
};
istream cin;
ostream cout;
void endl(ostream &os) {
putc('\n', os.steam_);
fflush(os.steam_);
}
void end(ostream &os) { fflush(os.steam_); }
struct pack {
int a;
int b;
friend istream &operator>>(istream &in, pack &cur);
friend ostream &operator<<(ostream &out, pack &cur);
};
istream &operator>>(istream &in, pack &cur) {
in >> cur.a;
in >> cur.b;
return in;
}
ostream &operator<<(ostream &out, pack &cur) {
out << cur.a;
out << " ";
out << cur.b;
out << endl;
return out;
}
int main() {
pack a, b;
cin >> a >> b;
cout << a << b;
return 0;
}