C++学习心得(1)运算符重载
——from 谭浩强.C++面向对象程序设计(第一版)
2014/10/6
4.1什么是运算符重载
用户根据C++提供的运算符进行重载,赋予它们新的含义,使之一名多用。
4.2运算符重载的方法
运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,以实现相应的运算。运算符重载实质上是函数的重载。
声明重载运算符+的函数:
Complex operator + (Complex &c2);
定义重载运算符+的函数:
函数返回值类型 operator 运算符名称 (形参列表)
{
对运算符的重载处理;
}
可以说:函数operator+重载了运算符 +
4.3 重载运算符的规则
<1>只能重载已有的C++运算符;
<2>不允许重载的运算符(5个):
.(成员访问运算符)
.*(成员指针访问运算符)
:: (域运算符)
sizeof(长度运算符)
?: (条件运算符)
<3>不能改变操作数的个数;
<4>不能改变优先级;
<5>不能改变结合性
<6>重载运算符的函数不能有默认参数;
<7>重载运算符的函数参数不能全部是C++标准类型,(至少有一个是类对象或类对象的引用)防止用户修改用于标准类型数据的运算符的性质。
<8>”=”和”&”不必用户重载;
<9>重载运算符功能应类似于其用于标准类型时所实现的功能;
<10>运算符重载函数可以是类的成员函数,类的友元函数,普通函数。
4.4 运算符重载函数作为类成员函数和友元函数
#include <iostream>
using namespace std;
class Complex
{
public:
Complex() { real= 0; imag = 0; }
Complex(doubler, double i) { real = r; imag = i; }
friendComplex operator + (Complex &c1, Complex &c2);
voiddisplay();
private:
doublereal;
doubleimag;
};
Complex operator + (Complex &c1,Complex &c2)
{
returnComplex(c1.real+c2.real, c1.imag+c2.imag);
}
void Complex::display()
{
cout<< "(" << real << "," << imag<< "i)" << endl;
}
int main()
{
Complexc1(3, 4), c2(5, -10), c3;
c3= c1 + c2;
cout<< "c1 = "; c1.display();
cout<< "c2 = "; c2.display();
cout<< "c1 + c2 = "; c3.display();
return0;
}
在将运算符”+”重载为友元函数后,编译系统将c1+c2解释为
operator + (c1, c2)
如果将运算符重载函数作为成员函数,必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。
将双目运算符重载为友元函数时,不要求第一个参数必须为类对象,但使用运算符的表达式中,要求运算符左侧的操作数与第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。数学上的交换律在此不适用。
一般将单目运算符重载为成员函数,将双目运算符重载为友元函数。
4.5 重载双目运算符
没什么好谈的,简单的看一下字符串的初始化。
声明构造函数:
String(char *);
定义构造函数:
String::String(char* str)
{
p = str;
}
初始化:
String string1(“Hello”);
4.6 重载单目运算符
#include <iostream>
using namespace std;
class Time
{
public:
Time(){ minute = 0; sec = 0; }
Time(intm, int s):minute(m), sec(s) {}
Timeoperator ++ (); // 声明前置自置运算符
Timeoperator ++(int); // 声明后置自增运算符
voiddisplay()
{
cout<< minute << ":" << sec << endl;
}
private:
intminute;
intsec;
};
Time Time::operator ++ ()
{
if(++sec>= 0)
{
sec-= 60;
++minute;
}
return*this; // 返回的是自加后的当前对象
}
Time Time::operator ++ (int)
{
Timetemp(*this);
sec++;
if(sec>= 60)
{
sec-= 60;
++minute;
}
returntemp; // 返回的是自加前的对象
}
int main()
{
Timetime1(34, 59), time2;
cout<< "time1:";
time1.display();
++time1;
cout<< "++time1:";
time1.display();
time2= time1++;
cout<< "time1++";
time1.display();
cout<< "time2:";
time2.display();
return0;
}
C++约定:如果在自增/自减运算符重载函数中,增加一个int型形参,就是自增/自减运算符函数。
Time operator ++ ();
Time operator ++ () (int);
不论是前置自增运算符还是后置自增运算符作用于变量或者对象都会有自增的效果。两个函数返回的结果是不同的,前置的返回的是修改后的对象本身,后置的返回的是自加前的对象。
4.7 重载流插入运算符和流提取运算符
输入流类istream
输出流类ostream
函数形式如下:
friendistream & operator >> (istream &, 自定义类 &);
friendostream & operator << (ostream &, 自定义类 &);
函数的返回值类型和第一个参数都必须是 istream &类型,第二个参数是要进行输入的操作的类。
只能将重载”>>”和”<<”的函数作为友元函数或普通函数,而不能将它们定义为成员函数。
声明:
friend ostream& operator << (ostream &, Complex &);
定义:
ostream & operator << (ostream & output, Complex &c)
{
output << "(" <<c.real << "+" << c.imag << "i)" <<endl;
return output;
}
函数中的形参output是ostream类对象的引用,形参名output是用户任意起的。编译器将cout << c3解释为
operator<<(cout, c3)调用函数。return output的作用是连续向输出流插入信息。将输出流cout的现状返回,即保留输出流现状。
4.8 不同类型数据间的转换
隐式类型转换
显示类型转换C++:int(89.5)而语言是C(int)89.5
4.8.2 利用转换构造函数进行类型转换
转换构造函数的作用是将一个其他类型的数据转换成一个指定的类的对象。
几种构造函数:
(1)默认构造函数; Complex();
(2)初始化构造函数; Complex(double r, doublei);
(3)复制构造函数; Complex(Complex &c);
(4) 转换构造函数; Complex(double r) { real = r; imag = 0; };
几处运用:(无名对象)
(1)c1 = Complex(3.6);
(2)c = c1 + Complex(3.6);
通常把有一个参数的构造函数用作类型转换,所以称为转换构造函数,但有一个参数的构造函数也可以不用作类型转换。不仅可以将一个标准数据类型转换成类对象,也可以将另一个类的对象转换成构造函数所在的类对象。一定要注意对象中的数据必须是公用成员才可以被类外引用。
4.8.3 用类型转换函数进行类型转换
类型转换函数的作用是将一个类的对象转换成另一个类型的数据。
类型转换函数的形式:
operator类型名 ()
{
实现转换的语句;
}
函数没有参数,因为不需要。也没有函数返回值类型,因为其返回值类型是由函数名中指定的类型名确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(){ real = 0; imag = 0; } //默认构造函数
Complex(doubler) { real = r; imag = 0;} // 转换构造函数
Complex(doubler, double i) { real = r; imag = i; } //初始化的构造函数
friendComplex operator + (Complex c1, Complex c2); //重载运算符“+”的友元函数
voiddisplay();
private:
doublereal;
doubleimag;
};
Complex operator + (Complex c1, Complex c2)
{
returnComplex(c1.real+c2.real, c1.imag+c2.imag);
}
void Complex::display()
{
cout<< "(" << real << "," << imag<< "i)" << endl;
}
int main()
{
Complexc1(3, 4), c2(5, -10), c3;
c3= c1 + 2.5;
c3.display();
return0;
}
转换构造函数和类型转换运算符有一个共同的功能:当需要的时候编译器会自动地调用这些函数,建立一个无名的临时对象,即隐式调用。
总结:将单目运算符重载为成员函数,将双目运算符重载为友元函数。