C++ IO流


写在开头:

本文是对公众号C/C++编程实验室中第一二章内容学习的总结.


主要内容:

  1. 自定义输出流对象输出到控制台
  2. 自定义输出流对象输出到文件
  3. 标准IO流对象(iostream)输出到控制台
  4. 打印自定义类型
  5. fstream对文件进行读写

  • 自定义输出流对象输出到控制台

    先要有一个My_String类
    通过自定义流对象,将My_String的对象输出到控制台
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class My_String {
public:
My_String();
My_String(const char* str);
My_String(const My_String&);
~My_String();
int length()const
{
return m_len;
}
My_String& operator=(const My_String&);
My_String& operator=(const char*);
char& operator[](int i);
const char& operator[](int i) const;
friend bool operator<(const My_String& str1, const My_String& str2);
friend bool operator>(const My_String& str1, const My_String& str2);
friend bool operator==(const My_String& str1, const My_String& str2);
friend ostream& operator<<(ostream &os, const My_String &str);
friend istream& operator >> (istream &is, My_String &str);
int size () const{ return strlen(m_str); } //const成员函数,不会改变对象
char* c_str() const { return m_str; }
private:
char* m_str;
int m_len;
};
定义输出流对象的基类MyStrIobase。

基类中的虚函数send用来在不同的子类中被继承,以实现多种功能(输出到控制台,或者输出到文件中),体现C++多态思想。

1
2
3
4
5
class MyStrIobase {
public:
virtual ~MyStrIobase() {}
virtual void send(const char* ptr, int n) {}
};
定义输出流对象类OStream,并继承基类

OStream能将My_String打印到控制台

在OStream重载send函数,将字符数组打印到控制台

1
2
3
4
5
6
7
8
9
10
class OStream :public MyStrIobase{
public:
void send(const char* ptr, int n)
/*ptr要打印的字符数组,n字符长度*/
{
for (int i = 0; i < n; ++i)
putc(*ptr++, stdout);
putc('\n', stdout);
}
};
重载<<运算符

可以用模板函数

1
2
3
4
5
template<class T> T& operator<<(T& io, const My_String& str)
{
sendstr(io, str.c_str(), str.size());
return io;
}

也可以专门为OStream重载一个<<

1
2
3
4
5
OStream& operator <<(OStream& io, const My_String& str)
{
sendstr(io, str.c_str(), str.size());
return io;
}
需要定义sendstr函数

这里参数是基类MyStrIobase,便于实现更多的功能,比如输出到文件的类,只需要继承基类MyStrIobase 就可以使用sendstr函数,不需要重新定义。

1
2
3
4
void sendstr(MyStrIobase& strio, const char* ptr, int n)
{
strio.send(ptr, n);
}

  • 自定义输出流对象输出到文件

    定义输出到文件的流对象类————FileOStream

    FileOStream也集成基类MyStrIobase,用来重载send函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     class FileOStream :public MyStrIobase {
    public:
    FileOStream(const char* filename, char* mode)
    {
    m_File = fopen(filename, mode);
    }
    void send(const char* str, int len)
    {
    if (m_File == nullptr || len < 0)
    return;
    for (int i = 0; i < len; ++i)
    putc(*str++, m_File);
    }
    void close()
    {
    fclose(m_File);
    m_File = nullptr;
    }
    private:
    FILE* m_File{ nullptr };
    };

    在FileOStream 构造函数中打开文件。

  • 标准IO流对象(iostream)输出到控制台

    标准ostream对象也可以输出My_String对象,重载sendstr,是sendstr而不是send,因为ostream不能去继承自定义的类型MyStrIobase

    1
    2
    3
    4
    void sendstr(ostream& os, const char* ptr, int n)
    {
    os.write(ptr, n);
    }
  • ostream 打印自定义类型 MInt

    需要重载<< ,>>运算符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    	/*打印自定义类型  MInt*/
    class MInt {
    public:
    MInt(int val) :mVal(val) {}
    MInt(const MInt& other) :mVal(other.mVal) {}
    friend ostream& operator<<(ostream& os, const MInt& other);
    friend istream& operator >> (istream& is, MInt& out);
    private:
    int mVal;
    };
    ostream& operator<<(ostream& os, const MInt& other) {
    os << other.mVal;
    return os;
    }
    istream& operator >> (istream& is, MInt& out) {
    is >> out.mVal;
    return is;
    }
    ````
    ---
    - #### fstream对文件进行读写

    /* 用标准库fstream来对文件进行读写*/
    void writetofile1()
    {
    /构造函数中打开文件/
    /fstream对象的输入输出模式out in ,可以参考CPlusPlus网站/
    ofstream outFile(“2.txt”, std::ios::out);
    /因为fostream类中重载了<< >>,这里直接用/
    outFile << “this is test writetofile1 pro!” << endl;
    outFile.close();
    }
    void writetofile2()
    {
    ofstream outFile;
    /open函数打开文件/
    outFile.open(“3.txt”, std::ios::out);
    outFile << “this is test writetofile2 pro!” << endl;
    outFile.close();
    }
    void writefromfile1()
    {
    /先将内容写进文件/
    ofstream outFile;
    outFile.open(“4.txt”, std::ios::out);
    outFile << “this is test writefromfile1 pro!” << endl;
    outFile.close();
    ifstream inFile(“4.txt”, std::ios::in);
    /也可以用open函数打开/
    string str;
    /std::getline读一行内容,注意是std命名空间中的getline,fstream泪也有一个getline函数,
    但用法不一样,std::getline 原型istream& getline (istream& is, string& str);
    istream.getline()原型 istream& getline (char
    s, streamsize n );*/
    std::getline(inFile, str);
    cout << str << endl;
    inFile.close();
    }

    1
    2
    ---
    - #### 测试以上案例

    void test1()
    {
    static My_String str(“this is a test!”);
    OStream Out;
    Out << str;
    /*测试iostream输出My_String*/
    cout << str << endl;;
    /*测试输出到文件*/
    FileOStream Fout(“1.txt”,”w+”);
    Fout << str;
    Fout.close();
    /*测试打印自定义类型MInt*/
    MInt m(0);
    cout << m << endl;
    cout << “enter a integer :” << endl;
    cin >> m;
    cout << m << endl;
    writetofile1();
    writetofile2();
    writefromfile1();
    }

    1
    2
    3
    4
    - #### [源代码](https://github.com/east1203/CPlusPlus.git)
    io流 和 mycase文件
    - #### 问题
    模板函数如果定义在cases.h文件中出错,最后把它定义在main函数所在的文件中

    /如果定义在cases.h中出错,识别不了My_String 类型/
    template T& operator<<(T& io, const My_String& str)
    {
    sendstr(io, str.c_str(), str.size());
    return io;
    }
    ```


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!