第11章 使用类
1.运算符重载:
(1)调用operator+()方法:
total=coding.operator+(fixing); //函数表示法
total=coding+fixing; //运算符表示法
(2)重载限制
a.重载后的运算符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载运算符。例如,减法运算符(-)计算两个double值的差,而不是和
b.使用运算符时不能违反运算符原来的句法规则。例如,不能将求模运算符(%)重载成使用一个操作数
c.不能修改运算符的优先级
d.不能创建新运算符,如不能定义operator**()函数来表示求幂
e.不能重载下面的运算符
——sizeof:sizeof运算符
——.:成员运算符
——.*:成员指针运算符
——:::作用域解析运算符
——?::条件运算符
——typeid:一个RTTI运算符
——const_cast:强制类型转换运算符
——dynamic_cast:强制类型转换运算符
——reinterpret_cast:强制类型转换运算符
——static_cast:强制类型转换运算符
f.只能通过成员函数进行重载:
=:赋值运算符
():函数调用运算符
[ ]:下标运算符
—>:通过指针访问类成员运算符
(3)重载加法运算符(+)、重载减法运算符(—)、重载乘法运算符(*)
Time operator+(const Time & t) const;
Time operator—(const Time & t) const;
Time operator*(double n) const;
2.友元
(1)友元函数类声明:
friend Time operator *(double m, const Time & t);
说明:operator*()函数是非成员函数,因此不能使用成员运算符来调用;
operator*()函数的访问权限和成员函数一样
(2)友元函数定义:不使用关键字friend,不使用(::)限定符
Time operator*(double m,const Time & t)
{
Time result;
long totalminutes=t.hours*mult*60+t.minutres*mult;
result.hours=totalminutes/60;
result.minutes=totalminutes%60;
return result;
}
提示:如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以用友元函数来反转操作数的顺序
3.常用的友元:重载<<运算符
(1)<<的第一种重载版本
可以通过使用友元函数,像下面这样重载运算符:
void operator<<(ostream & os,const Time & t)
{
os<<t.hours<<" hours, "<<t.minutes<<" minutes";
}
故可使用下面的语句: cout<<trip;
(2)<<的第二种重载版本
ostream & operator<<(ostream & os, const Time & t)
{
os<<t.hours<<" hours, "<<t.minutes<<" minutes";
return os;
}
故可使用下面的语句: cout<<"Trip time: "<<trip<<" (Tuesday)\n
4.重载运算符:作为成员函数还是非成员函数
Time operator+(const Time & t)const; //成员函数
friend Time operator+(const Time & t1,const Time & t2); //友元函数
对成员函数版本来说,一个操作数通过this指针隐式地传递,另一个操作数作为函数参数显式地传递;对于友元版本来说,两个操作数都作为参数来传递
编译器将下面的语句:T1=T2+T3
转换为下面两个的任何一个:
T1=T2.operator+(T3);
T1=operator+(T2,T3);
5.矢量Vector类
(1)状态成员:描述对象所处的状态,如 enum Mode{RECT,POL};
(2)为Vector类重载算术运算符:如果方法通过计算得到一个新的类对象,则应考虑是否可以使用类构造函数来完成这种工作。这样做不仅可以避免麻烦,而且可以确保新的对象是按正确的方式创建的。
(3)将数据写入文件中:
#include<fstream>
.....
ofstream fout;
fout.open("thewaslk.txt");
然后在计算结果的循环中加入类似于下面的代码:
fout<<result<<endl;
这将调用友元函数operator<<(fout,result),导致引用参数os指向fout,从而将输出写入到文件中
(4)多种表示方式:设计类时,将使得用户修改了矢量的一种表示后,对象自动更新另一种表示,使对象有这种智能,是C++类的另一个优点。
6.类的自动转换和强制类型转换
(1)当构造函数只接受一个参数时,可以使用下面的格式来初始化类对象:
Stonewt incognito=275; //隐式类型转换
Stonewt incognito(275);
Stonewt incognito=Stonewt(275);
注意:只接受一个参数的构造函数定义了从参数类型到类类型的转换。如果使用关键字explicit限定了这种构造函数,则它只能用于显式转换,否则也可以用于隐式转换
(2)转换函数:operator typeName();
注意:转换函数必须是类方法(转换函数为类成员);转换函数不能指定返回类型;转换函数不能有参数
(3)C++11中可以使用expicit显式声明转换函数:
class Stonewt
{
.....
explicit operator int() const;
explicit operator double() const;
};
另一种方法是,用一个功能相同的非转换函数替换转换函数,但仅在被显式地调用时,该函数才会执行
Stonewt::operator int() { return int(pounds+0.5); }
//替换为:
int Stonewt::Stone_to_Int() { return int(pounds+0.5); }
int plb=poppins.Stone_to_Int(); //转换
7.重载加法运算符:
(1)使用成员函数:如果运算符是类成员函数,则第一个操作数是调用对象
Stonewt Stonewt::operator+(const Stonewt &st) const
{
double pds=pounds+st.pounds;
Stonewt sum(pds);
reyurn sum;
}
(2)使用友元函数
Stonewt operator+(const Stonewt & st1, const Stonewt & st2)
{
double pds=st1.pounds+st2.pounds;
Stonewt sum(pds);
return sum;
}