[C++] 重载运算符与类型转换(1)
2024-09-01 07:00:31
1、形式:返回值 operator符号(参数列表){}
2、不能被重载的运算符::: 作用域运算符 .* . 成员访问运算符 ?: 条件运算符;某些运算符(逗号,,取地址&,逻辑或||,逻辑与&&)不应该被重载:1)重载之后无法保留运算对象的求值顺序,比如逻辑与&&,逻辑或||和逗号运算符;2)无法保留运算符的短路求值属性,比如&&和||;3)有特殊含义的运算符,比如逗号和取地址。
3、建议:只有当操作的含义对于用户来说清晰明了时才使用运算符,否则运算符将产生二义性。
4、两种选择:作为类的成员函数或者作为普通的非成员函数
5、重载输出运算符
//定义
ostream& operator<<(ostream &os, const Sales_data &item) {
os << item.isbn() <<" "<<item.units_sold<< "——重载输出运算符";
return os;
}
1)尽量减少格式化操作
2)输入输出运算符必须是非成员函数
3)IO运算符一般被声明为友元
friend ostream& operator<<(ostream&, const Sales_data&);
friend istream& operator >> (istream&, Sales_data&);
6、重载输入运算符
//重载输入运算符
istream& operator >> (istream &is, Sales_data &item) {
double price;
is >> item.bookNo >> item.units_sold >> price;
if (is) //检查输入是否成功
item.revenue = item.units_sold*price;
else
item = Sales_data();//输入失败:对象赋予默认状态
return is;
}
调用
/*重载运算符操作,调用*/
Sales_data sales_data;
operator >> (cin, sales_data);//输入
operator<< (cout, sales_data)<<endl;//输出
1)输入运算符必须处理输入可能失败的情况,而输出运算符不需要
7、算数和关系运算符
1)通常情况下,我们把算数和关系运算符定义成非成员函数,以允许对左侧或右侧的运算对象进行转换。
2)相等和不等关系运算符
//相等运算符——包括相等和不等判断,要求所有数据成员对应相等
bool operator==(const Sales_data &lhs, const Sales_data &rhs) {
return lhs.isbn() == rhs.isbn()&&lhs.units_sold==rhs.units_sold&&lhs.revenue==rhs.revenue;
}
bool operator!=(const Sales_data &lhs, const Sales_data &rhs) {
return !(lhs == rhs);
}
3)大于小于关系运算符:如果存在唯一一种可靠的<定义,则应该考虑为这个类定义<运算符。如果类同时还包含==,则当且仅当<的定义和==产生的结果一致时才定义<运算符。也就是说,只要不是==,就一定有一个小于另一个。
8、赋值和复合赋值运算符
1)无论形参是什么,赋值运算符都必须定义为成员函数。
//赋值运算符
StrVec& StrVec::operator=(initializer_list<string> il) {
//alloc_n_copy分配内存空间并从给定范围内靠背元素
auto data = alloc_n_copy(il.begin(), il.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
2)复合赋值运算符定义在类的内部,两者都返回左侧运算对象的引用
//复合赋值运算符
Sales_data& Sales_data::operator+=(const Sales_data &rhs) {
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
9、算数运算符
1)算术运算符定义为非成员函数,通常使用定义的复合赋值运算符来定义对应的算术运算符,这样可以简化过程。
//算数运算符--返回对象的拷贝
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs) {
Sales_data sum = lhs;
sum += rhs;
return sum;
}
10、下标运算符
1)下标运算符必须是成员函数。
2)如果一个类包含下标运算符,则它通常会定义两个版本:一个返回普通引用,另一个是类的常量成员并返回常量引用。
//下标运算符
string& StrVec::operator[](size_t n) {
return elements[n];
}
const string& StrVec::operator[](size_t n) const{
return elements[n];
}
11、递增和递减运算符
1)前置递增和递减
StrBlobPtr& StrBlobPtr::operator++() {
check(curr,"increment past end of StrBlobPtr");//如果已经指向了容器的尾后位置,那么无法继续递增它
++curr;
return *this;
}
StrBlob& StrBlobPtr::operator--() {
--curr;
check(curr, "decrement past end of StrBlobPtr");
return *this;
}
a、递增和递减应该同时定义前置版本和后置版本,通常应该定义为类的成员函数。
b、为了区分前置和后置运算符,后置版本接受一个额外的(不被使用)int类型的形参。
c、后置操作调用了前置操作。
d、为了与内置版本保持一致,前置运算符返回对象的引用,而后置运算符返回原来对象的一个拷贝。
2)后置递增和递减
//后置递增和递减
StrBlobPtr StrBlobPtr::operator++(int) {
StrBlobPtr ret = *this;
++(*this);//调用前置的操作
return ret;
}
StrBlobPtr StrBlobPtr::operator--(int) {
StrBlobPtr ret = *this;
--(*this);
return ret;
}
3)调用
//重载前置和后置递增递减运算符
StrBlobPtr p;
p.operator++();//调用后置运算符
p.operator++();//调用前置运算符
12、成员访问运算符
1)箭头运算符必须是类的成员函数,解引用运算符通常也是。
2)因为访问成员不会改变对象状态,所以定义为const。
3)注意箭头运算符的限定,P505
//成员访问运算符
string& StrBlobPtr::operator*()const {
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
string* StrBlobPtr::operator->()const {
//将实际工作委托给解引用运算符
return &(this->operator*());
}
最新文章
- Linux系统挂载数据盘
- 开启 CONFIG_HUGETLB_PAGE
- poj1166学习中
- HTML5 中canvas支持触摸屏的签名面板
- mysql PDO的使用
- 重拾C,一天一点点_3
- 让DataGridView显示行号
- c# 强制退出程序
- dotnetcore vue+elementUI 前后端分离架二(后端篇)
- 小黄鸡机器人和小I机器人的调用
- BZOJ 1260:[CQOI2007]涂色paint
- bzoj4490 随机数生成器Ⅱ加强版
- html前端优化建议
- 实例化和设置一个优秀的php对象
- notepad++列块编辑操作
- WPF RichTextBox自动调整高度
- iPhoneX设计尺寸和适配
- [csp-201809-4]再卖菜 差分约束or记忆化搜索
- activiti源码分析学习
- R ggplot2 线性回归
热门文章
- 关于《Selenium3自动化测试实战--基于python语言》
- Flink快速入门--安装与示例运行
- vsftpd 530 Login incorrect问题处理
- runnable和thread实现多线程的区别
- [Python] Django框架入门
- 从SpringBoot构建十万博文聊聊限流特技
- 【HDU5409】CRB and Graph 边双联通 子树最值
- 2019杭电多校 hdu6662 Acesrc and Travel (树形dp
- 堆实战(动态数据流求top k大元素,动态数据流求中位数)
- 三个小白是如何在三个月内搭一个基于kaldi的嵌入式在线语音识别系统的