• 手动实现iostream


    本人在OI中很长时间(直到现在)是cstdio党;也就是说很不习惯用stl,虽然我也不知道具体的原因。

    不过一直用scanf、printf是很麻烦的。比如下面的A+B问题:

    #include<cstdio>
    int main(){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d",a+b);
        return 0;
    }
    A+B(cstdio)

    如代码所示,每次都要用%格式符格式化,不写不行;scanf还要额外用取址符&,不用不行。这样是很麻烦的!有时候会想如果cin、cout没有那么慢的话,在OI里可能就用了,毕竟很方便:

    #include<iostream>
    int main(){
         int a,b;
         cin>>a>>b;
         cout<<a+b;
         return 0;
    }
    A+B(iostream)

    说到速度,OI里有时候会用读入输出优化:

    #include<cstdio>
    int read(){
        int x=0,w=1,c=getchar();
        while(c<'0'||c>'9'){
        if(c=='-') w=0;
        c=getchar();
        }
        while(c>='0'&&c<='9'){
        x=(x<<3)+(x<<1)+(c-'0');
        c=getchar();
        }
        return w?x:-x;
    }
    void write(int a){
        if(a<0) putchar('-'),a=-a;
        if(a>9) write(a/10);
        putchar(a%10+'0');
        return;
    }
    int main(){
        int a,b;
        a=read();
        b=read();
        write(a+b);
        return 0;
    }
    A+B(优化)

    本人一直有着这种关于cin、cout的想法。后来在紫书中看lrj实现BigInt类,重载了<<和>>。那之后我就查了stl的输入输出流是怎么写的。于是今天就想着自己实现一个输入输出流,这样可能会很方便。

    iostream中关于输入输出有两个基类:标准输入流(class istream)和标准输出流(class ostream)。这两个流分别重载了>>运算符和<<运算符。还有一些派生类,比如fstram、sstream之类的。

    拿istream举例。istream重载>>运算符用于输入流。每次读入一个变量,再返回一个流。重载的伪代码如下:

    class istream{
        public:
        //以int举例
            istream operator >> (int &a){
                //读入整型并赋值给a(伪代码)
                return *this;
            }
    };
    >>重载(伪代码)

    最后return一个流,这样可以连续地读入(像cin>>a>>b一样)。顺便一提,这个重载实际写成了virtual,为了使fstream之类的重载。顺便一提,这个代码不是从stl里copy的,只是本蒟蒻yy出来的……不过思路差不多。

    有了这个思路,我们就可以写输入流了!为了解决伪代码里的读入整型的问题,同时解决cin的速度问题,我们可以使用读入优化!

    代码如下:

    class istream{
            //以int举例
        public:
            int read(){
                int x=0,w=1,c=getchar();
                while(c<'0'||c>'9'){
                    if(c=='-') w=0;
                    c=getchar();
                }
                while(c>='0'&&c<='9'){
                    x=(x<<3)+(x<<1)+(c-'0');
                    c=getchar();
                }
                return w?x:-x;
            }
            istream operator >> (int &a){
                a=read();
                return *this;
            }
    };
    >>重载

    输出流是一样的道理~

    代码如下:

    class ostream{
            //以int举例
        public:
            void write(int a){
                if(a<0) putchar('-'),a=-a;
                if(a>9) write(a/10);
                putchar(a%10+'0');
                return;
            }
            ostream operator << (const int &a){
                write(a);
                return *this;
            }
    };
    <<重载

    这样我们就可以像cin、cout一样读入、输出整数了。

    字符串也可以这样搞。如果是单个字符,可以用getchar()、putchar()来写。如果是字符串就这么搞:

    class istream{
        public:
            void getstr(char a[]){
                int i=0;
                char c;
                do{
                    c=getchar();
                    a[i++]=c;
                }while(c!=EOF&&c!=26&&c!=0&&c!=' '&&c!='
    '&&c!='
    '); 
            //这里判断是否已经读入完。EOF是文件输入时的文件结束符
            //加上EOF可以兼容freopen。26是控制台输入^Z的值,其实
            //^Z和EOF是一样的,只不过EOF的值是-1,如果输入不以回车
            //或空格结束,那么不加26这个判断就不会结束控制台读入。
                a[i-1]=0;
            //这一步将串的最后置为0,表示串到此结束。
            //scanf也是这么操作的。
                return;
            }
            istream operator >> (char a[]){
                getstr(a);
                return *this;
            }
    };
    class ostream{
        public:
            void write(const char a[]){
                int i=0;
                while(a[i]!=0) putchar(a[i++]);
                return;
            }
            ostream operator << (const char a[]){
                write(a);
                return *this;
            }
    };
    字符串重载

    这样搞支持freopen重载之后的文件输入输出,但不支持fopen的方式。

    这样我们就可以用流的方式输入输出字符和字符串了!

    整数和字符的完整输入输出流(注:这里把两个流写在一起,不需要特别注意分别输入和输出的情况下效果是一样的):

    #include<cstdio>
    class IO{
        public:
            int getint(){
                int x=0,w=1,c=getchar();
                while(c<'0'||c>'9'){
                    if(c=='-') w=0;
                    c=getchar();
                }
                while(c>='0'&&c<='9'){
                    x=(x<<3)+(x<<1)+(c-'0');
                    c=getchar();
                }
                return w?x:-x;
            }
            long long getlong(){
                long long x=0;
                int w=1,c=getchar();
                while(c<'0'||c>'9'){
                    if(c=='-') w=0;
                    c=getchar();
                }
                while(c>='0'&&c<='9'){
                    x=(x<<3)+(x<<1)+(c-'0');
                    c=getchar();
                }
                return w?x:-x;
            }
            void getstr(char a[]){
                int i=0;
                char c;
                do{
                    c=getchar();
                    a[i++]=c;
                }while(c!=EOF&&c!=26&&c!=0&&c!=' '&&c!='
    '&&c!='
    '); 
                a[i-1]=0;
                return;
            }
            void write(int a){
                if(a<0) putchar('-'),a=-a;
                if(a>9) write(a/10);
                putchar(a%10+'0');
                return;
            }
            void write(long long a){
                if(a<0) putchar('-'),a=-a;
                if(a>9) write(a/10);
                putchar(a%10+'0');
                return;
            }
            void write(const char a[]){
                int i=0;
                while(a[i]!=0) putchar(a[i++]);
                return;
            }
            virtual IO operator >> (int &a){a=getint();return *this;}
            virtual IO operator >> (long long &a){a=getlong();return *this;}
            virtual IO operator >> (char &a){a=getchar();return *this;}
            virtual IO operator >> (char a[]){getstr(a);return *this;}
            virtual IO operator << (const int &a){write(a);return *this;}
            virtual IO operator << (const long long &a){write(a);return *this;}
            virtual IO operator << (const char &a){putchar(a);return *this;}
            virtual IO operator << (const char a[]){write(a);return *this;}
    }get,put;
    输入输出流

    最后为这个IO类实现两个实例:get和put,就可以当成加速的cin和cout了(如果不用stl可以直接实现成cin和cout,用着习惯)。

    如果自己实现了一个什么其他的类,也可以重载一个运算符,这样就可以用在这个类上了。比如: 

    class Pair{
        friend IO operator >> (IO in,Pair &a);
        friend IO operator << (IO out,const Pair &a);
        private:
            int f,s;
        public:
            Pair(int ff=0,int ss=0){
                f=ff;
                s=ss;
            }
    };
    IO operator >> (IO in,Pair &a){
        return in>>a.f>>a.s;
    }
    IO operator << (IO out,const Pair &a){
        return out<<'('<<a.f<<','<<a.s<<')';
    }
    Pair重载流

    stl里的流也可以这样重载,只不过参数的流和返回的流都要加引用。

    最后一提,这里面没有实数,但是实数的读入优化也是可以写的,有兴趣可以自己试一试。只不过cout实数是像printf的%g一样,自动判断小数点后有效位数(去除后导0),这个暂时不知道怎么写……

    谁还记得我写这个的初衷是想要写着方便来着……

  • 相关阅读:
    神仙题1.0
    一些小技巧(持续更新。。)
    模板(持续更新中。。)
    「CTS2019 | CTSC2019」氪金手游(容斥+概率计数)
    Emacs配置
    AGC034E Complete Compres(dp)
    「清华集训 2017」榕树之心(换根dp)
    [NOI2018]冒泡排序 (卡特兰数)
    「清华集训 2017」小 Y 和二叉树 (贪心)
    「雅礼集训 2018 Day1」图 (dp套dp)
  • 原文地址:https://www.cnblogs.com/halifuda/p/8406315.html
Copyright © 2020-2023  润新知