十四章、重载操作符
十四章、重载操作符
一、重载操作符的定义: 保留字operator后接需要定义的操作符符号,同时具有返回类型和形参表;如:Sales_item operator+ (const Sales_item&,const Sales_item&);
1、 除了函数调用操作符之外,重载操作符的形参数目与操作符的操作数数目相同,函数调用操作符可以接受任意数目的操作符。
2、 重载操作符必须具有一个类类型操作数,内置类型的操作符其含义不能改变;(重载操作符必须具有至少一个类类型或枚举类型)
3、 作为类成员的重载函数,有一个隐含的this形参,限定为第一个操作数(左操作数)。
4、 Cout << item1 + item2 << endl; 这个表达式隐式调用了Sales_item operator+
5、 重载操作符的设计:不要重载具有内置含义的操作符
(1) 合成赋值操作符进行逐个成员赋值
(2) 默认情况下,取地址操作符(&)和逗号操作符(,)在类类型对象上的执行与在内置类型对象上的执行一样。
(3) 内置逻辑与(&&)和逻辑或(||)使用短路求值,如果重新定义该操作符,将失去操作符的短路求值特征。
6、 为类设计操作符,最好的方式是首先设计类的公用接口。定义了接口之后就可以考虑将那些操作符定义为重载操作符。如:
- ·相等测试操作应使用operator == ;
- ·一般通过重载一位操作符进行行输入和输出;
- ·测试对象是否为空的操作可以用逻辑非操作符operator!表示。
7、 选择成员或非成员师兄:
·赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员。
·复合赋值操作符通常定义为类的成员。
·自增或自减和解引用通常定义为类成员。
·算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。
二、输入和输出操作符:为了与IO标准库一致,操作符应接受ostream&/istream&作为顶一个形参,对类类型const对象的引用作为第二个行程,并返回ostream/istream形参的引用。
1、 salse_item的输出操作符:
- ostream& operator<<(ostream& out,const Sales_item& s)
{
Out << s.isbn << “\t” << s.units_sold << “\t” << s.revenue << “\t” << s.avg_price() ;
Return out ;
}
(如果IO操作符是类成员,则左操作数将智能是该类类型的对象,所以必须为非成员函数,同时,类通常将IO操作符设为友元)
2、 输入操作符 >> 重载:Sales_item 的输入操作符
Istream& operator>> (istream& in ,Sales_item& s)
{
Double price;
In >> s.ibsn >> s.units _sold >> price ;
If (In)
s.revenue = s.units_sold * price ;
else
s = Sales_item() ;
}
输入期间的错误:
(1) 任何读操作都可能因为提供的值不正确而失败。如读入isbn之后,输入操作符将期望下两项是数值型数据。如果输入非数值型数据,这次的读入以及流的后续将都是失败。
(2) 任何读入都可能碰到输入流中的文件结束或其他一些错误。
如果有错,具体做法是创建一个新的、未命名的、使用默认构造函数的Sales_item对象并将它赋值给s。赋值后,s的isbn是空string,revenue和units_sold为0.
三、算术操作符和关系操作符:一般,将算术和关系操作符定义为非成员函数。
1、 相等操作符:
Inline bool operator==(const Sales_item &lhs,const Sales_item &rhs)
{
Return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue &&
lhs.same_isbn(rhs) ;
}
Inline bool operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
Return !(lhs == rhs) ;
}
函数所包含的设计原则:
- ·如果类定义了==操作符,该操作符的含义是两个对象包含同样的数据。
- ·如果类具有一个操作,能确定该类型的两个对象是否相等,通常将该函数定义为operator==,而不是创造命名函数。
- ·如果类定义了operator==,应该也定义operator!=
- ·相等和不相等操作符一般应该联系定义。一个完成对象操作,另一个只需要调用前者。如上面函数。
四、赋值操作符: 赋值操作符必须定义为成员函数,必须返回对*试试的引用!
五、下标操作符:类定义下标操作符时,一般需要两个版本:一个非const成员的返回引用,另一个const成员的返回const引用!
1、 原型下标操作符: 简化,假定Foo所保存的数据储存在一个vector<int>中:
Class Foo
{
Public:
Int &operator[] (const size_t);
Const Int &operator[] (const size_t)const ;
Private:
Vector<int> data;
}
下标操作符:
Int & Foo::operator[] (const size_t index)
{
Return data[index] ;
}
Const int & Foo::operator[](const size_t index) const
{
Return data[index] ;
}
六、自增和自减操作符
1、 ++I ,--I 形式:
声明形式:
Class CheckedPtr
{
Public:
CheckedPtr& operator++();
CheckedPtr& operator- -();
} ;
函数具体形式:
CheckedPtr& CheckedPtr::operator++()
{
If(curr == end)
Throw out_of_range(”increment past the end of CheckedPtr”);出错处理
++cuur ;
Return *this ;
} // ++i
CheckedPtr& CheckedPtr::operator--()
{
If(curr == end)
Throw out_of_range(”increment past the end of CheckedPtr”);出错处理
--cuur ;
Return *this ;
} // --i
2、 i++ / i—形式:
声明形式:
Class CheckedPtr
{
Public:
CheckedPtr& operator++(int);
CheckedPtr& operator- -(int);
} ;
为了区分++i和i++,将重载操作符函数增加了一个无用的int形参,一般可以传一个0进来。
此时操作符应该返回旧值(尚未自增,自减的值),是值返回,而不是返回引用。
CheckedPtr& CheckedPtr::operator++(int)
{
CheckedPtr ret(*this) ;
++*this ;
Return ret ;
} // i++
CheckedPtr& CheckedPtr::operator--(int)
{
CheckedPtr ret(*this) ;
--*this ;
Return ret ;
} // i--