C++ 标准库 —— iostream

1、istream 和 ostream 

1.1、istream类

istream 类用于从标准输入设备(例如键盘)或其他输入设备(如文件)读取数据,它是所有输入流类的基类。

常用的成员函数

operator>>:提取运算符,用于从输入流中提取数据。

>> 的实现原理

ostream 类中,<< 操作符被重载为一个函数,该函数能够处理各种类型的输出,比如整型、浮点型、字符串等。每次使用 << 时,数据都会传递给该运算符函数,最终输出到流所指向的设备上(如终端或文件)。典型的输出运算符重载形式为:

std::ostream& operator<<(std::ostream& os, int value);
std::ostream& operator<<(std::ostream& os, double value);
std::ostream& operator<<(std::ostream& os, const char* str);

链式调用的原理

<< 操作符的返回值是对输出流对象本身的引用(std::ostream&),这使得链式调用成为可能。如下面例子,std::cout << "x = " 返回的是 std::ostream&,接着 x 通过下一个 << 操作符继续输出。

std::cout << "x = " << x << ", y = " << y;

get():从输入流中获取一个字符或字符数组。

char ch;
std::cin.get(ch);  // 读取一个字符

getline():从输入流中读取一行字符串。

std::string line;
std::getline(std::cin, line);  // 读取一行字符串

1.2、ostream 类

ostream 类用于将数据输出到标准输出设备(例如屏幕)或其他输出设备,它是所有输出流类的基类。

常用的成员函数

operator<<:插入运算符,用于将数据输出到流中(实现原理与 >> 类似)。

put():输出一个字符。

std::cout.put('A');  // 输出字符 'A'

write():输出一系列字符。

char str[] = "C++ Programming";
std::cout.write(str, sizeof(str));  // 输出字符串

2、iostream

iostream 类是 istreamostream 的派生类,能够同时执行输入和输出操作,通常用于文件或其他双向通信的场景。

为什么不直接设计一个 iostream,转而先设计 istream 和 ostream 呢?

  1. 在设计流类时,将输入和输出职责分开,使每个类的职责更加明确,便于理解和维护。这符合单一职责原则,即每个类应该只负责一件事情。
  2. 分离 istreamostream 为两个独立的类为以后的扩展提供了更大的灵活性。例如ifstream 类只需要处理文件输入,它只需继承 istream 即可,而 ofstream 类只处理文件输出,它继承自 ostream。在某些特殊情况下,程序既需要处理输入也需要处理输出,iostream 就发挥了作用(fstream 同时用于文件读写)。

2.1、标准输入输出对象

iostream 库中,已经定义了一些常用的全局流对象:

  • std::cin:标准输入流,通常与键盘关联,用于从标准输入读取数据。
  • std::cout:标准输出流,通常与显示器关联,用于向标准输出设备(屏幕)输出数据。
  • std::cerr:标准错误输出流,通常与显示器关联,用于输出错误信息,不带缓冲。
  • std::clog:标准日志输出流,通常用于输出日志信息,带缓冲。
int age;
std::cin >> age;  // 从键盘读取一个整数
std::cout << "Hello, World!" << std::endl;  // 向屏幕输出 "Hello, World!"
std::cerr << "Error: Invalid input" << std::endl;  // 输出错误信息
std::clog << "Log: Application started" << std::endl;  // 输出日志信息

std::cinstd::coutstd::cerr 和 std::clog 的本质

这四个标准流对象本质上是全局对象。它们是 C++ 标准库中定义的对象,专门用于处理标准输入、标准输出和错误输出的流操作。根据标准库的定义,这些流对象大致是以如下方式声明的(虽然实际的实现可能会有所不同):

namespace std {
    extern istream cin;   // 标准输入
    extern ostream cout;  // 标准输出
    extern ostream cerr;  // 标准错误输出(无缓冲)
    extern ostream clog;  // 标准日志输出(带缓冲)
}

2.2、格式化输出

通过 iostream,可以对输出进行格式化。以下是几种常用的格式化方法:

  • std::endl:输出换行并刷新输出缓冲区。

  • std::setw():设置字段宽度,定义在 iomanip 头文件中。

  • std::setprecision():设置浮点数的精度,定义在 iomanip 头文件中。

  • std::fixedstd::scientific:设置浮点数的显示格式。

std::cout << "Hello, World!" << std::endl;

std::cout << std::setw(10) << 123;  // 输出的数字宽度为10个字符

double pi = 3.14159;
std::cout << std::setprecision(3) << pi;  // 输出为 3.14

double num = 1234.56789;
std::cout << std::fixed << num;       // 以固定小数点格式输出
std::cout << std::scientific << num;  // 以科学计数法格式输出

std::endl 的本质

本质上是一个函数,而不是一个简单的换行符。它的功能不仅仅是插入换行符(\n),它还会刷新输出缓冲区,确保缓冲区中的数据被立即输出到设备(如终端、文件等)。std::endl 是定义在 ostream 类中的模板函数,它的声明通常如下:

namespace std 
{
    template <class charT, class traits>
    basic_ostream<charT, traits>& endl(basic_ostream<charT, traits>& os) 
    {
        os.put(os.widen('\n'));   // 插入换行符
        os.flush();               // 刷新缓冲区
        return os;
    }
}

2.3、状态标志

在使用 iostream 进行输入输出时,流可能会出现一些错误情况,比如输入格式不正确、文件结束等。C++ 提供了一些函数和状态标志来检查流的状态:

eof():检查是否到达文件末尾。

if (std::cin.eof()) 
{
    std::cout << "End of file reached" << std::endl;
}

fail():检查上一次输入操作是否失败。

if (std::cin.fail()) 
{
    std::cerr << "Input failed!" << std::endl;
}

bad():检查是否发生严重的输入输出错误。

if (std::cin.bad()) 
{
    std::cerr << "A critical error occurred!" << std::endl;
}

clear():重置流的状态标志。

std::cin.clear();  // 清除所有错误标志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值