类中的流操作符的重载

📅 2026/7/24 20:46:56
类中的流操作符的重载
目录摘要一理解cout的本质二操作符的重载问题1参数颠倒问题2无法访问私有成员变量问题3无法连续使用问题4最终版本三操作符的重载四细节补充摘要本文实现类中的流操作符的重载也就是和的重载我们只需理解的重载就可以同理理解的重载.....一理解cout的本质首先我们要理解cout这个东西因为我们使用是和cout一起使用的https://legacy.cplusplus.com/reference/iostream/cout/?kwcout以上官网中对cout的描述如下解释:我们只用知道以下即可①cout 是类 ostream 的对象它是一个全局的已经定义好的 ostream 类的对象②我们cout的形式写入数据时cout是作为对象调用这个运算符重载函数③该对象在头文件 iostream 中声明具有外部链接和静态存储期它在程序的整个生命周期内存在所以我们直接就能使用❓️cout会自动识别类型的本质是什么①类ostream中已经给你实现好了多种操作符的各种重载所以对于不同的内置类型都可以进行识别和操作②而count是类ostream的对象调用了类ostream中的函数所以cout 等同于cout.operator(123);对于双操作数的运算符的理解对于的认识需知系统规定双操作数的运算符第一个参数是左操作数第二个参数是右操作数所以是一个双操作数的操作符第一个参数为左操作数cout第二个参数为右操作数变量二操作符的重载上面类ostream中实现的多种对于操作符的重载都是针对内置类型的而我们自己实现的类也想使用和则需要自己手动实现一个针对类类型的操作符的重载。但是实现过程会遇见多个问题将这些问题逐一解决则可以正确实现问题1参数颠倒类中的声明class Date { public: Date(int year, int month, int day) { _year year; _month month; _day day; } void Print() const { printf(%d-%d-%d\n, _year, _month, _day); } void operator(ostream out); private: int _year; int _month; int _day; };类外的定义void Date::operator(ostream out) { out _year / _month / _day endl; }main函数中的使用发现main函数中无法使用解释①如需知所言所以我们平时写的coutd1cout就是的第一个参数d1是的第二个参数但是当我们像上面那样写第一个参数是隐藏的this所以和我们想要的相反此时d1 cout 是可以的②所以我们要避免第一个参数被this占据所以将操作符重载声明和定义都写在类外也就是全局函数问题2无法访问私有成员变量类外的声明void operator(ostream out, const Dated); //而第一个参数不加const是因为 其会改变 记住就行类外的定义void operator(ostream out, const Date d) { out d._year / d._month / d._day endl; }解释此时在声明中就会报错因为全局函数没有权限访问私有成员变量所以我们还得在类中的声明处给该函数加上友元关键字让该函数可以访问私有成员变量问题3无法连续使用如下class Date { public: friend void operator(ostream out, const Date d); // 友元的声明 //... private: int _year; int _month; int _day; };新的问题无法 cout d1 d2而真正的cout是可以连续的进行打印的这是因为类ostream中实现的操作符的重载函数的返回值是ostream类型所以当连续使用的时候返回值作为下一次的参数就实现了连续的打印而我们的返回值是void当然不能cout d1 d2啦~连续插入 d1 和 d2 实际上就是两次函数的调用这里先执行的是coutd1解决方案我们把返回值改为 ostream 就行把 out这个对象返回回去。问题4最终版本进行如下的改进类中的声明class Date { public: // ... friend ostream operator(ostream out, const Date d); // 友元的声明 private: int _year; int _month; int _day; };类外的定义#include Date.h ostream operator(ostream out, const Date d) { out d._year / d._month / d._day endl; return out; }main中使用int main(void) { Date d1(2022, 3, 20); Date d2(2021, 5, 1); cout d1 d2; return 0; }此时在main函数可以连续的打印了三操作符的重载和是同理的只不过是istream的对象所以代码如下类中的声明class Date { public: // ... friend ostream operator(ostream out, const Date d); friend istream operator(istream in, Date d); private: int _year; int _month; int _day; };类外的的定义#include Date.h istream operator(istream in, Date d) { in d._year d._month d._day; return in; }main函数中的使用int main(void) { Date d1(2022, 3, 20); Date d2(2021, 5, 1); printf(请输入两个日期:\n); cin d1 d2; printf(你输入的日期是:\n); cout d1 d2; return 0; }解释和cout类似cin是istream类的全局对象四细节补充Q1为什么上面实现的函数中out和in参数都没有使用const修饰Q2为什么上面实现的函数中返回值都采取引用返回可以采取值返回吗Q3使用流提取符的重载函数中为什么参数Date不用const修饰起到保护作用Q4为什么scanf要取地址而cin不用A1out和in就是cout和cin的引用所以这个问题可以转化为为什么不能对cout和cin使用const修饰这是因为不管是cout打印还是cin读取都会对cout或cin的对象产生改变会修改流内部的缓冲区、状态位和格式标志所以不能const修饰A2首先采用引用返回是因为这个返回对象再函数栈帧销毁之后仍存在所以可以起到避免拷贝的效果其次也不能采取值返回因为不管是ostream类还是istream类的拷贝构造都是被禁用的禁用的原因不作过多解释A3因为会改变对象是把用户输入的值赋值给对象的成员变量所以Date会被改变自然不能让Date被const修饰而的参数Date因为不会被改变所以可以const修饰A4因为scanf要改变变量所以需要得到变量的地址而cin不需要因为C有引用 [ 作者 ] shylyly [ 首次发布 ] 2025.3.1❌ [ 最新修改 ] 2026.7.23 [ 声明 ] 由于笔者水平有限文中难免有疏漏或不妥之处还望读者不吝赐教