C++ 中流插入(<<)与提取(>>)运算符重载解析

C++ 中流插入(<<)与提取(>>)运算符重载解析

一、运算符重载的基本规则

  • 运算符本质
    <<>> 是二元运算符,左操作数为流对象(istream/ostream),右操作数为自定义类型对象。例如:cout << obj 实际调用的是 operator<<(cout, obj)cin >> obj 调用的是 operator>>(cin, obj)

  • 必须重载为友元函数
    由于左操作数是流对象(非类成员),需将运算符重载函数声明为类的 友元函数,以便访问类的私有成员。

  • 返回流对象的引用
    返回流对象的引用(ostream&istream&)是为了支持链式调用,例如 cout << a << b


二、流插入运算符 << 重载

1. 语法格式

// 声明为类的友元函数
friend ostream& operator<<(ostream& os, const MyClass& obj);

// 函数实现
ostream& operator<<(ostream& os, const MyClass& obj) {
    os << obj.data1 << ", " << obj.data2; // 按需访问和输出成员
    return os;
}

2. 示例:输出学生信息

#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;
    int age;
public:
    Student(string n, int a) : name(n), age(a) {}
    // 声明为友元函数
    friend ostream& operator<<(ostream& os, const Student& s);
};

// 实现 << 运算符重载
ostream& operator<<(ostream& os, const Student& s) {
    os << "Name: " << s.name << ", Age: " << s.age;
    return os;
}

int main() {
    Student s("Alice", 20);
    cout << s; // 输出:Name: Alice, Age: 20
    return 0;
}

三、流提取运算符 >> 重载

1. 语法格式

// 声明为类的友元函数
friend istream& operator>>(istream& is, MyClass& obj);

// 函数实现
istream& operator>>(istream& is, MyClass& obj) {
    is >> obj.data1 >> obj.data2; // 按需读取数据
    return is;
}

2. 示例:输入学生信息

class Student {
    // 假设需要以下成员
    string name;
    int age;
public:
    Student() {}
    // 声明友元函数
    friend istream& operator>>(istream& is, Student& s);
};

// 实现 >> 运算符重载
istream& operator>>(istream& is, Student& s) {
    cout << "Enter name and age: ";
    is >> s.name >> s.age; // 读取数据
    return is;
}

int main() {
    Student s;
    cin >> s; // 输入数据到 s
    cout << s; // 输出(假设 << 已重载)
    return 0;
}

四、关键注意事项

  1. 输入参数必须为非 const 引用
    因为 >> 运算符需要修改对象状态。

    istream& operator>>(istream& is, Student& s); // 正确
    
  2. 处理输入错误
    >> 重载中应检查输入合法性,例如年龄不能为负数:

    if (!(is >> s.age)) {
        cerr << "Invalid input!";
        is.setstate(ios::failbit);
    }
    
  3. 链式调用的实现
    返回流引用允许连续操作:

    Student s1, s2;
    cin >> s1 >> s2;
    
  4. 避免修改流状态
    不要随意更改流的格式(如 hexsetw),以免影响后续操作。


五、综合示例:日期类输入输出

#include <iostream>
using namespace std;

class Date {
private:
    int year, month, day;
public:
    Date(int y=0, int m=0, int d=0) : year(y), month(m), day(d) {}
    friend ostream& operator<<(ostream& os, const Date& d);
    friend istream& operator>>(istream& is, Date& d);
};

// 输出运算符重载
ostream& operator<<(ostream& os, const Date& d) {
    os << d.year << "-" << d.month << "-" << d.day;
    return os;
}

// 输入运算符重载
istream& operator>>(istream& is, Date& d) {
    char dash1, dash2;
    is >> d.year >> dash1 >> d.month >> dash2 >> d.day;
    // 验证格式
    if (dash1 != '-' || dash2 != '-' || d.month < 1 || d.month > 12) {
        is.setstate(ios::failbit);
    }
    return is;
}

int main() {
    Date d;
    cout << "Enter date (YYYY-MM-DD): ";
    cin >> d;
    if (cin.fail()) {
        cerr << "Invalid date format!";
    } else {
        cout << "Date: " << d << endl; // 输出日期
    }
    return 0;
}

六、总结

  1. 友元声明:必须将运算符重载函数声明为类的友元。
  2. 返回流引用:确保支持链式调用。
  3. 输入验证:在 >> 重载中处理非法输入。
  4. 参数类型<< 的第二个参数为 const 引用,>> 的第二个参数为非 const 引用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值