C++类与对象笔记十二:运算符重载二:左移运算符重载
左移运算符重载:可以打印输出自定义数据类型。
为了输出重载,我们先看看现有的输出函数。输出类型为std下的ostream类型的引用。
标准输出流(全局只能有一个)。
返回值类型为ostream,函数名称operator<<,输入参数为我们自定义类型。
仿照加号运算符重载,我们先试试成员函数。
ostream& operator<<(Person& p) {}
利用成员函数重载 左移运算符调用情形:p.operator<<(p)。先有一个对象调用函数,然后还要输入一个对象。这不是我们期望的:cout << p;的情景。简写方式只能通过p << cout方式调用。
我们把cout也加入进去:返回一个ostream类型,这样可以形成链式编程。
ostream& operator<<(ostream& cout)
{cout << "这个对象的m_A的值为:" << this->m_A << "这个对象的m_B的值为:" << this->m_B;return cout;
}
这样成员函数的输入是一个ostream流的引用,输出也是一个ostream流的引用,可以满足链式需求。
调用情况:
Person p(11, 22);
// 直接调用:
//p.operator<<(cout) << endl;
// 返回类型:调用方式一。
//ostream& out = p.operator<<(cout) << endl;
// 支持这种调用。
//p << cout << endl;
输出:
这个对象的m_A的值为:11。 这个对象的m_B的值为:22
代码:
#include<iostream>
using namespace std;
#include<string>class Person
{
public:Person(int a, int b){this->m_A = a;this->m_B = b;}ostream& operator<<(ostream& outStream){outStream << "这个对象的m_A的值为:" << this->m_A << "。 这个对象的m_B的值为:" << this->m_B;return outStream;}public:int m_A;int m_B;
};void test01()
{Person p(11, 22);// 直接调用://p.operator<<(cout) << endl;// 返回类型://ostream& out = p.operator<<(cout) << endl;// 支持这种调用。p << cout << endl;
}
int main()
{test01();system("pause");return 0;
}
调用方式是:p<< cout。方向反了,我们希望的场景是:cout << p;
利用成员函数实现这样的场景不行了。只能采用全局函数的形式。
一般不会利用成员函数重载左移运算符<< ,因为无法实现cout在左侧的情况。只能用全局函数来实现。
简写方式是cout << p;所以应该是cout在左,在前,p在右,在后。定义一个全局函数:
void operator<<(cout, Person p) {} // 本质:operator<<(cout, p)简化形式可以写成cout << p;
本质:operator(cout, p),可简化写为:cout << p;
上面我们查到cout的类型为ostream;然后为了保证cout的全局唯一性:我们输入cout的引用。
补充函数:
void operator<<(ostream& cout, Person p) // 本质:operator<<(cout, p)简化形式可以写成cout << p;
{cout << "m_A = " << p.m_A << "; m_B = " << p.m_B;
}
此时可调用如下:
void test02()
{Person p(11, 22);operator<<(cout, p);//cout << p;
}
简化调用没问题。本质调用operator<< 也没问题。
但是cout支持链式编程,即可以在后面不断接<<,所以应该返回对于cout本体的引用。
全局函数变更为:将局部变量名换成out也可以。
ostream& operator<<(ostream& out, Person p) // 本质:operator<<(out, p)简化形式可以写成cout << p;
{out << "m_A = " << p.m_A << "; m_B = " << p.m_B;return out;
}
还剩最后一个问题:
在类内:一般我们把字段设置为私有private。这样在类外基于全局函数的运算符重载将无法访问到字段,所以整套的做法:要把全局函数的重载声明作为友元放在类内。
#include<iostream>
using namespace std;
#include<string>class Person
{friend ostream& operator<<(ostream& out, Person p);
public:Person(int a, int b){this->m_A = a;this->m_B = b;}//ostream& operator<<(ostream& outStream)//{// outStream << "这个对象的m_A的值为:" << this->m_A << "。 这个对象的m_B的值为:" << this->m_B;// return outStream;//}private:int m_A;int m_B;
};ostream& operator<<(ostream& cout, Person p) // 本质:operator<<(cout, p)简化形式可以写成cout << p;
{cout << "m_A = " << p.m_A << "; m_B = " << p.m_B;return cout;
}void test02()
{Person p(11, 22);//operator<<(cout, p) << endl;cout << p << endl;}
void test01()
{Person p(11, 22);// 直接调用://p.operator<<(cout) << endl;// 返回类型://ostream& out = p.operator<<(cout) << endl;// 支持这种调用。//p << cout << endl;
}
int main()
{test02();cout;system("pause");return 0;
}
需要总结的几点:结合上一个案例加号运算符重载:发现
- 运算符重载作为类内成员函数,在调用时是p1.operator+(p2)。可简写为p1+p2。或者p2+p1。
- 运算符重载作为类外全局函数,在调用时是opearator(p1, p2)。可简写为p1+p2。后者p2+p1。
- 也就是说必须类内成员函数输入参数有一个二元运算符中的一元,类外一元作为一元。
- 类外全局函数输入参数是二元运算符中的两个元。
- 加号无所谓方向要求。左移运算符因为有方向和顺序,所以无法用类内成员函数实现。在全局实现中也要注意参数顺序。
- 链式编程返回本体引用。
C++类与对象笔记十二:运算符重载二:左移运算符重载相关推荐
- C++类与对象笔记十四:多态六:虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构代码. 即:父类指针无法调用子类实例对象内的析构函数.造成堆区内存泄漏. 解决方案:将父类中的析构函数改为虚析构或者纯虚析 ...
- Kotlin学习笔记 第二章 类与对象 第十二 十三节 对象表达式与对象声明 类型别名
参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...
- Kotlin学习笔记 第二章 类与对象 第十四 十五节 委托 委托属性
参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...
- C++_类和对象_C++运算符重载_左移运算符重载_链式编程_实现直接打印对象---C++语言工作笔记056
然后我们再去看左移运算符,实际上就是那个<< 小于号 为什么要重载他呢?因为我们想实现一个功能,比如我仅仅是cout << p 就可以打印这个对象,现在肯定是不行对吧. 我们用 ...
- c++,运算符重载,左移运算符自增运算符。
假设有类A,它的私有成员是一个整型变量a_ A a; 我们想要把它的私有成员直接用 cout<<a<<endl 输出的话要用到左移运算符的重载. 我们把<<运算符重 ...
- 运算符重载之左移运算符重载
左移运算符重载 #include<iostream> using namespace std; class wood {friend ostream& operator<&l ...
- Kotlin学习笔记 第二章 类与对象 第十节 内部类嵌套类
参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...
- PHP的类与对象-笔记
对象的赋值: 手册中有如下一个例子,个人理解如下 $assigned = $instance; $reference =& $instance; $instance--->var = ' ...
- 【C++ 七】类和对象:封装、继承、多态、友元、运算符重载
封装.继承.多态.对象的初始化和清理.C++对象模型和this指针.友元.运算符重载 文章目录 封装.继承.多态.对象的初始化和清理.C++对象模型和this指针.友元.运算符重载 前言 1 封装 1 ...
最新文章
- 2021-2027年中国智能马桶盖行业市场研究及前瞻分析报告
- Centos7上openVP-密钥登陆
- 《配置管理最佳实践》——2.10 建立构建过程
- IntelliJ IDEA 15发布
- bootstrap-select采坑
- Redux API之applyMiddleware
- 【机器学习】总结:线性回归求解中梯度下降法与最小二乘法的比较
- 栈应用:实现二进制转八进制、十进制、十六进制
- tcpip详解有必要看吗_车辆有必要安装“行车记录仪”吗?如何挑选看这里!
- 绘图之使用工作空间直接绘图
- 树莓派 4b 可执行文件 无法双击运行_树莓派01 - 树莓派系统安装
- 湖北随州:借大数据“慧眼”织密扶贫监督网
- 常数除以0的极限是什么_【高数总结求极限方法】百度作业帮
- 天气实况、天气预报、免费天气接口、空气质量各类天气数据、生活指数、气候数据雷达云图等值面...
- java hook api 实现封包截取_hook 封包 截取WSASend实例
- c0704 学生记录
- C/C++编程:std::move(将左值强制转换为右值)
- cocos2d编写android插件,[分享]Xposed插件dump Cocos2d-x应用的lua脚本
- 一个程序员的自白(认同迷失)
- 【黑盒测试】 正交排列法设计测试用例