C++ Stream 类层次结构深度解析


下面我将对 C++ I/O 流类层次结构进行更加深入和详细的解析,包括每个类的设计目的、关键成员函数、使用场景以及更完整的代码示例。

1. ios_base- 流的基础设施

ios_base是所有流类的根基,不依赖于字符类型或流缓冲区,提供流的基础设施。

核心功能

  1. 格式化标志管理

    • fmtflags类型定义:hex, dec, oct, left, right, scientific, fixed

    • setf(), unsetf(), flags()操作标志

  2. 异常处理

    • iostate类型定义:goodbit, eofbit, failbit, badbit

    • exceptions()设置异常掩码

  3. 本地化

    • imbue()设置本地化环境
  4. 扩展存储

    • xalloc(), iword(), pword()提供用户自定义存储

详细示例

#include <iostream>
#include <locale>

void formatFlagsDemo() {
    // 保存当前标志
    std::ios_base::fmtflags old_flags = std::cout.flags();
    
    // 设置十六进制输出,显示基数前缀,宽度10,左对齐
    std::cout.setf(std::ios_base::hex | std::ios_base::showbase | std::ios_base::left, 
                  std::ios_base::basefield | std::ios_base::adjustfield);
    std::cout.width(10);
    std::cout << 255 << std::endl;  // 输出 "0xff      "
    
    // 恢复标志
    std::cout.flags(old_flags);
}

void exceptionHandlingDemo() {
    std::cin.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    
    try {
        int value;
        std::cout << "Enter an integer: ";
        std::cin >> value;  // 输入非数字会触发异常
    } catch (const std::ios_base::failure& e) {
        std::cerr << "I/O error: " << e.what() << '\n';
        if (std::cin.rdstate() & std::ios_base::failbit) {
            std::cin.clear();  // 清除错误状态
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
    }
}

void localizationDemo() {
    // 使用德国本地化环境,数字中使用逗号作为小数点
    std::cout.imbue(std::locale("de_DE"));
    std::cout << 1234.56 << std::endl;  // 输出 "1.234,56"
    
    // 恢复默认本地化
    std::cout.imbue(std::locale());
}

int main() {
    formatFlagsDemo();
    exceptionHandlingDemo();
    localizationDemo();
    return 0;
}

2. basic_ios- 流的核心管理

basic_ios是类模板,管理流的状态和缓冲区,是 basic_istreambasic_ostream的直接基类。

核心功能

  1. 流状态管理

    • rdstate(), setstate(), clear()

    • good(), eof(), fail(), bad()

  2. 缓冲区管理

    • rdbuf(), rdbuf(streambuf*)
  3. 格式化上下文

    • copyfmt()复制格式化设置
  4. 填充字符

    • fill(), fill(char)

详细示例

#include <iostream>
#include <fstream>
#include <sstream>

void streamStateDemo() {
    std::ifstream file("nonexistent.txt");
    
    // 检查流状态
    if (file.fail()) {
        std::cout << "File open failed. State: ";
        if (file.rdstate() & std::ios_base::badbit) 
            std::cout << "badbit ";
        if (file.rdstate() & std::ios_base::failbit) 
            std::cout << "failbit ";
        if (file.rdstate() & std::ios_base::eofbit) 
            std::cout << "eofbit ";
        std::cout << '\n';
    }
}

void bufferManagementDemo() {
    std::filebuf fb;
    if (fb.open("test.txt", std::ios::out)) {
        std::ostream os(&fb);
        os << "Writing to file via streambuf\n";
        fb.close();
    }
    
    // 重定向 cout
    std::streambuf* old_buf = std::cout.rdbuf();
    std::ofstream file("cout_redirect.txt");
    std::cout.rdbuf(file.rdbuf());
    std::cout << "This goes to file\n";
    std::cout.rdbuf(old_buf);
    file.close();
}

void formatCopyDemo() {
    std::ostream os(nullptr);  // 无缓冲区
    
    // 从 cout 复制格式化设置
    os.copyfmt(std::cout);
    os.clear(std::cout.rdstate());
    
    // 设置新的缓冲区
    std::stringbuf sb;
    os.rdbuf(&sb);
    
    os << "Formatted like cout: " << std::hex << 255;
    std::cout << "Captured output: " << sb.str() << '\n';
}

int main() {
    streamStateDemo();
    bufferManagementDemo();
    formatCopyDemo();
    return 0;
}

3. basic_streambuf- 底层缓冲区抽象

basic_streambuf是流的核心,负责实际的 I/O 操作。

核心功能

  1. 缓冲区管理

    • pubsetbuf(), pubseekoff(), pubseekpos()

    • in_avail(), snextc(), sbumpc(), sgetc()

  2. 输入区域

    • underflow(), uflow(), showmanyc()
  3. 输出区域

    • overflow(), xsputn(), sync()
  4. 放置区域

    • pbackfail()

详细示例:自定义缓冲区

#include <iostream>
#include <streambuf>
#include <cstdio>

class TeeBuffer : public std::streambuf {
private:
    std::streambuf* src;
    std::ostream& copy;
    char buffer;
    
protected:
    int_type underflow() override {
        int_type ch = src->sbumpc();
        if (ch != traits_type::eof()) {
            buffer = ch;
            copy.put(ch);
            setg(&buffer, &buffer, &buffer + 1);
        }
        return ch;
    }
    
public:
    TeeBuffer(std::streambuf* src, std::ostream& copy) 
        : src(src), copy(copy) {}
};

class TeeStream : public std::istream {
private:
    TeeBuffer tb;
    
public:
    TeeStream(std::istream& in, std::ostream& copy) 
        : std::istream(&tb), tb(in.rdbuf(), copy) {}
};

int main() {
    // 将 cin 同时输出到 cout
    TeeStream tee(std::cin, std::cout);
    
    std::cout << "Type something (will echo): ";
    std::string input;
    tee >> input;
    std::cout << "\nYou typed: " << input << '\n';
    
    return 0;
}

4. basic_ostream- 高级输出接口

核心功能

  1. 插入操作

    • operator<<重载
  2. 定位

    • tellp(), seekp()
  3. 刷新

    • flush(), put(), write()

详细示例

#include <iostream>
#include <fstream>
#include <iomanip>
#include <bitset>

void outputOperations() {
    // 基本输出
    std::cout << "Standard output\n";
    
    // 无缓冲输出
    std::cerr << "Error message\n";
    
    // 格式化输出
    std::cout << std::boolalpha << true << ' ' << false << '\n';
    std::cout << std::hex << std::showbase << 255 << '\n';
    std::cout << std::scientific << 123.456 << '\n';
    
    // 原始输出
    const char* data = "Raw data";
    std::cout.write(data, 8).put('\n');
    
    // 二进制输出
    std::bitset<8> bits(0xAA);
    std::cout << bits << '\n';
}

void filePositioning() {
    std::fstream file("position.txt", std::ios::out | std::ios::in | std::ios::trunc);
    file << "Hello World";
    
    // 获取当前位置
    std::streampos pos = file.tellp();
    std::cout << "Current position: " << pos << '\n';
    
    // 移动到开头
    file.seekp(0, std::ios::beg);
    file << "HELLO";
    
    // 移动到末尾
    file.seekp(0, std::ios::end);
    file << "!!!";
    
    file.close();
}

int main() {
    outputOperations();
    filePositioning();
    return 0;
}

5. basic_istream- 高级输入接口

核心功能

  1. 提取操作

    • operator>>重载
  2. 无格式输入

    • get(), getline(), read(), readsome()
  3. 定位

    • tellg(), seekg()
  4. 忽略

    • ignore()

详细示例

#include <iostream>
#include <fstream>
#include <limits>
#include <iomanip>

void inputOperations() {
    // 基本输入
    int i;
    std::cout << "Enter an integer: ";
    std::cin >> i;
    
    // 处理错误
    if (std::cin.fail()) {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cerr << "Invalid input\n";
    } else {
        std::cout << "You entered: " << i << '\n';
    }
    
    // 行输入
    std::cout << "Enter a line: ";
    std::string line;
    std::cin.ignore();  // 清除之前的换行符
    std::getline(std::cin, line);
    std::cout << "Line: " << line << '\n';
    
    // 原始输入
    char buffer[10];
    std::cout << "Enter 5 characters: ";
    std::cin.read(buffer, 5);
    buffer[5] = '\0';
    std::cout << "Read: " << buffer << '\n';
}

void binaryFileReading() {
    std::ifstream file("data.bin", std::ios::binary);
    if (file) {
        // 获取文件大小
        file.seekg(0, std::ios::end);
        std::streamsize size = file.tellg();
        file.seekg(0, std::ios::beg);
        
        // 读取整个文件
        char* buffer = new char[size];
        file.read(buffer, size);
        
        // 处理二进制数据...
        
        delete[] buffer;
    }
}

int main() {
    inputOperations();
    binaryFileReading();
    return 0;
}

6. basic_iostream- 双向流

核心功能

  1. 同时继承 basic_istreambasic_ostream

  2. 用于需要同时进行输入输出的场景

  3. 常用于字符串流和文件流

详细示例

#include <iostream>
#include <sstream>
#include <string>

void stringStreamDemo() {
    std::stringstream ss;
    
    // 写入
    ss << "Number: " << 42 << " Pi: " << 3.14159;
    
    // 读取
    std::string token;
    while (ss >> token) {
        std::cout << "Token: " << token << '\n';
    }
    
    // 重置流
    ss.clear();
    ss.str("");  // 清空内容
    
    // 重新使用
    ss << "New content";
    std::cout << ss.str() << '\n';
}

void fileStreamDemo() {
    std::fstream file("data.txt", std::ios::in | std::ios::out | std::ios::trunc);
    
    if (file) {
        // 写入
        file << "Line 1\nLine 2\nLine 3\n";
        
        // 回到开头读取
        file.seekg(0);
        std::string line;
        while (std::getline(file, line)) {
            std::cout << "Read: " << line << '\n';
        }
        
        // 追加内容
        file.clear();  // 清除EOF标志
        file.seekp(0, std::ios::end);
        file << "Line 4\n";
        
        file.close();
    }
}

int main() {
    stringStreamDemo();
    fileStreamDemo();
    return 0;
}

总结

C++ 的流类层次结构提供了强大而灵活的 I/O 系统:

  1. 分层设计​:从底层的 basic_streambuf到高层的 basic_istream/basic_ostream

  2. 可扩展性​:可以通过派生自定义缓冲区或重载操作符来扩展功能

  3. 统一接口​:对控制台、文件、内存等不同设备提供一致的接口

  4. 国际化支持​:通过本地化支持多语言环境

  5. 类型安全​:类型安全的 I/O 操作

理解这些类的层次结构和相互关系对于开发高级 I/O 功能至关重要,特别是在需要自定义流行为或实现特殊 I/O 设备支持时。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐