- 一、引子:为什么要对运算符进行重载
- 二、对运算符重载的方法
- 结合代码详解:
- 三、运算符重载的规则
- 四、运算符重载函数作为类成员函数和友元函数
- 结合代码详解:
- 区别和选取:
- 二种方法的区别
- 选用的一些规则
- END
我们之前已经接触过函数的重载,所谓 重载 就是赋予一个新的含义,函数重载就是对于一个已经有的函数赋予新的含义,使之实现新的功能,也就是“一名多用”。C++中运算符的运算对象只能是基本数据类型,而不适用于用户自定义的数据类型(类),用于对已有的运算符进行重新定义,运算符重载相当于运算符的函数重载,赋予其另一种功能,以适应不同的数据类型。
实际上,我们已经不知不觉之中用到了运算符重载,例如,我们平时用的加法运算符 “+” 可以实现对于整数浮点数的运算,计算机处理这些数据时的操作方法有所差异,但是C++中已经对于加法运算符 “+” 重载,这样加法运算符 “+” 就可以使用于int,float,double等不同数据类型的运算。
按照我的一些理解以及编程过程中的一些体会,运算符重载在原理上面是将指定的运算表达式转换成对运算符函数的调用,可以实现需求的多样化,化繁为简,具有扩充性和适应性,下面我将先介绍使用方法后结合一些基础例题和详细代码共同来学习运算符重载。
重载运算符的函数一般格式如下:
函数类型 operator 运算符名称(形参列表)
{
运算符重载函数体;
}
注意:
- 重载为类成员函数时:
参数个数 = 原操作个数 - 1(后置++,–除外),因为类成员函数需要一个对象来调用,用来调用的那个对象其实就是另一个操作数,由于重载函数是Complex类中的成员函数,有一个参数是隐含的,运算符函数是用this指针隐式地访问类对象的成员。可以看到,重载函数operator+访问了两个对象中的成员,一个是this指针指向的对象中的成员,一个是形参对象中的成员。如this->real+c2.real,this->real就是c1.real例如 operator + 后面只需要传入一个参数; - 重载为非成员函数时;参数 = 原操作数个数,且至少应该有一个自定义类型的形参。(第四部分继续介绍)
上面格式里operator是运算符重载关键字,需要注意的是“operator 运算符名称”在一起是运算符重载函数的函数名,这样理解也就可以和定义函数串联起来,含义就是“重载了xx运算符”。理论学习之后直接进入代码部分:
结合代码详解:例1 对运算符“+”重载,使之可以实现两个复数相加。
#includeusing namespace std; class Complex { public: Complex() { real = 0;imag = 0; } Complex(double r, double i) { real = r;imag = i; } Complex operator + (Complex& c2); //声明重载运算符“+”的函数 void display(); private: double real; double imag; }; Complex Complex::operator + (Complex& c2) { Complex c; c.real = real + c2.real; c.imag = imag + c2.imag; //实现两个复数实部和虚部的相加 return c; } void Complex::display() { cout << "(" << real << "," << imag << "i" << ")" << endl; //输出最后的负数形式 (a,bi) } int main() { Complex c1(3, 4), c2(1, 2), c3; c3 = c1 + c2; //运算符“+”重载用于复数运算 cout << "c1 = ";c1.display(); //输出c1,c2,c3 cout << "c2 = ";c2.display(); cout << "c3 = ";c3.display(); }
代码的几点说明:
- 在运算符“+”重载为类的成员函数时,主函数里面 c1 + c2 C++编译系统解释为 c1.operator + (c2),表示为c2为实参来调用c1的运算符重载函数operator + 实现两个负数相加;
- 更加简洁可以修改operator + 代码部分:
Complex Complex::operator + (Complex& c2) {
return Complex(real + c2.real,imag + c2.imag); //建立临时对象调用构造函数
}
详细代码&&运行结果图片:
三、运算符重载的规则- C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
- C++不允许重载的运算符只有五个: . (成员访问运算符); * (成员指针运算符); :: (作用域运算符);sizeof(长度运算符);?: (条件运算符)。
- 重载不能改变运算符运算对象(即操作数)的个数。如关系运算符“>”和“<”等是双目运算符,重载后仍为双目运算符,需要两个参数。运算符“+”,“-”,“*”, “&”等既可以作为单目运算符,也可以作为双目运算符,可以分别将它们重载为单目运算或双目运算符。
- 重载不能改变运算符的优先级别。例如“*”和“/”优先于“+”和“-”,不论怎样进行重载,各运算符之间的优先级别不会改变。
- 重载不能改变运算符的结合性。如赋值运算符“=”是右结合性(自右至左),重载后仍为右结合性。
- 重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数,与前面第三点矛盾。
- **重载的运算符必须和用户自定义的类型对象一起使用,参数至少有一个是类的对象。**也就是说,参数不能全部是C++的标准类型,以防止用户修改标准数据类型运算符的性质,如下代码有错误:
int operator + (int a,int b){
return (a - b); //调用1+2的时候,结果是3还是-1??? 编译时已经出现错误
}
总体来说规则比较好理解,重在使用。
四、运算符重载函数作为类成员函数和友元函数 对于运算符重载函数的处理方式有两种:
(1)把运算符重载的函数作为类的成员函数;
(2)运算符重载的函数不是类的成员函数(可以是一个普通函数),在类中把它声明为友元函数。
上面例一已经实现了类的成员函数代码,下面继续结合复数运算来介绍友元运算符重载函数:
例2 对运算符“+”重载,使之可以实现两个复数相加,重载函数不作为成员函数而是放在类外作为Complex类的友元函数。
#includeusing namespace std; class Complex { public: Complex() { real = 0;imag = 0; } Complex(double r, double i) { real = r;imag = i; } friend Complex operator + (Complex& c1, Complex& c2); //重载函数作为友元函数 void display(); private: double real; double imag; }; Complex operator + (Complex& c1, Complex& c2) { //定义运算符 “+”重载函数 return Complex(c1.real + c2.real,c1.imag + c2.imag); } void Complex::display() { cout << "(" << real << "," << imag << ")" << endl; } int main() { Complex c1(1, 2), c2(3, 4), c3; c3 = c1 + c2; //解释为operator + (c1,c2); cout << "c1 = ";c1.display(); cout << "c2 = ";c2.display(); cout << "c3 = ";c3.display(); }
代码的几点说明:
在运算符“+”重载为类的成员函数时,主函数里面 c1 + c2 C++编译系统解释为 operator + (c1,c2);
详细代码&&运行结果图片:
看见上面两个代码的差距并不是很大,于是就会有这些疑问——什么时候应该用成员函数方式,什么时候应该用友元函数方式?二者有何区别呢?(以复数和整数运算来简要阐述)
二种方法的区别- 运算符重载函数作为成员函数,它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数。但必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。
例3-1 对运算符“+”重载,使之可以实现一个复数和一个整数相加。
#includeusing namespace std; class Complex { public: Complex() { real = 0;imag = 0; } Complex(double r, double i) { real = r;imag = i; } Complex operator + (int& i); private: double real; double imag; }; Complex Complex::operator + (int& i) { return Complex(real + i,imag); } int main() { Complex c1(1, 2), c3; int i = 0; cin >> i; c3 = c1 + i; //c3 = i + c1; //error,左边不是类对象无法调用运算符重载函数 }
- 如果运算符左侧的操作数属于C++标准类型(如int)或是一个其他类的对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。如果函数需要访问类的私有成员,则必须声明为友元函数。(构造即可,代码部分忽略)
(1)C++规定,赋值运算符 = 、下标运算符 [ ] 、函数调用运算符 () 、成员运算符 -> 必须是成员函数;
(2)流插入 << 和流提取运算符 >> 、类型转换运算符不能定义为类的成员函数,只能作为友元函数;
(3)一般将单目运算符和复合运算符重载为成员函数;
(4)一般将双目运算符重载为友元函数。
END
这一次主要是对于运算符重载的一个总体介绍,下一次会对单目运算符,双目运算符,流插入&&流提取运算符以及类型转换等知识点进行一个详细介绍和代码展示。



