【C++ 运算符重载入门:一篇搞懂「为什么重载」「怎么重载」「何时重载」】

C++ 运算符重载入门:一篇搞懂「为什么重载」「怎么重载」「何时重载」
一.多态性
定义:在C++程序设计中,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,这样就可以用同一个函数名调用不同内容的函数。分类:编译时的多态和运行时的多态编译时的多态性:
(1)静态联编:静态联编是指系统在编译时就决定如何实现某一动作。静态联编要求在程序编译时就知道如何调用函数的全部信息。
(2)编译时的多态性:静态联编支持的多态性称为编译时的多态性,也称为静态多态性。
编译时的多态通过函数重载(包括运算符重载)和模版实现。运行时的多态性:
(1)动态联编:动态联编是指系统在运行时动态实现某一动作,采用这种联编方式,一直要到程序运行时才能确定调用哪个函数。
(2)动态多态性:动态联编所支持的多态性称为运行时多态性,也称为动态多态性。
运行时的多态性通过虚函数实现。
二.运算符重载
C语言中的运算符
从不同角度看运算符:
运算对象个数: 单目,双目运算符的本质:函数C++重载:能重载,不能重载重载方式:类外,友元,成员函数
什么是运算符重载:
定义 :两个或者两个以上的运算符函数共用一个运算符函数名为运算符函数重载。用于完成“+”,“-”,“*”,“/”等操作的函数为运算符函数.C++规定运算符函数名为:
* operator+
* operator-
* operator*
* operator/等
* 统称为operator@
C++系统已经预先编好了两个基本数据类型相加的运算符函数,可以直接使用他们。但C++系统预先编号的运算符函数不能完成两个对象的相加工作。
int main()
{
complex x1,x2;
complex total=x1+x2;
//错误,无法完成
......
}
类以外的运算符重载
解决办法是自己写一个实现两个对象相加的运算符函数
1. class complex {
2. public:
3. double real, imag;
4. complex(double r=0,double i=0){real=r;imag=i;}
5. };
6. complex operator+(complex co1,complex co2){
7. complex temp;
8. temp.real=co1.real+co2.real;
9. temp.imag=co1.imag+co2.imag;
10. return temp;
11.}
12. int main( ) {
13. complex com1(1.1,2.2),com2(3.3,4.4),total1,total2;
14. total1=operator+(com1,com2);//调用运算符函数operator+()的第1种方式
15. cout<<"real1="< 16. cout <<" imag1=" < 17. total2=com1+com2; //调用运算符函数operator+()的第2种方式 18. cout<<"real2="< 19. cout <<" imag2="< 20. return 0; 21.} 说明:C++对运算符重载制定了以下规则: (1) C++中绝大部分的运算符允许重载,不能重载的运算符只有以下几个: * “.” 成员访问运算符 * “*” 成员指针访问运算符 * “::” 作用域运算符 * sizeof 长度运算符 * ?: 条件运算符 (2) 只能对已有的C++运算符进行重载,不允许用户自己定义新的运算符。 * 例如:不能重载!因为他不是c++运算符 (3)在重载运算符时,运算符函数所作的操作不一定要保持c++中该运算符原有的含义。例如可以把加运算符重载成减操作,一般保持原含义,不容易混乱。 (4) 重载不能改变运算符的操作对象(即操作数)的个数 (5)重载不能改变运算符原有的优先级 (6) 重载不能改变运算符原有的结合特性,例如*和/在c++中都是左结合的 例:x=a/b*c 等价于x=(a/b)*c (7) 运算符重载函数的参数至少有一个是类对象(或者类对象的引用),也就是说,运算符重载函数的参数不能全部是C++标准类型。 ```c++ int operator+(int x,int y) { return x+y;//这是错误的 } ``` (8) 运算符重载函数,本质上来说是,“具有固定名称的普通参数”,他可以出现在类外,也可以作为类的成员函数,也可以作为类的友元函数,以友元形式出现的重载较为常见。 (9)用于类对象的运算符必须重载,但是**赋值运算符“=”例外,不必用户进行重载**因为c++系统已为每一个新声明的类重载了一个赋值运算符函数。 友元运算符重载函数 因为定义在类外无法访问类中私有成员和保护成员,所以可以采用友元或成员函数。 定义友元运算符重载函数的语法形式 (1) 在类的内部,定义友元运算符重载函数的格式如下:firend 函数类型 operator运算符(形参表) { } (2) 友元运算符重载函数也可以在类中声明友元函数的原型,在类外定义。 在类中声明友元运算符重载函数原型的格式如下: c++ class X{ ... friend 函数类型 operator运算符(形参表); .... } 在类外定义友元运算符重载函数的格式如下: c++ 函数类型 operator运算符 (形参表) { 函数体 } 实例: c++ class complex { friend complex operator+(compex c1,complex c2);//在类中声明 } complex operator+(complex c1,complex c2)//在类外定义 { } 友元运算符函数定义时: 若重载的是双目运算符,则参数表中只有两个操作数若重载的是单目运算符,则参数表中只有一个操作数 双目运算符重载 (1)双目操作符有两个操作数,通常在运算符的左右两侧,例如: 3+5,24>12 当用友元函数重载双目运算符时,两个操作数都要传递给运算符重载函数。 (2)可以采用以下两种方式调用: * aa@bb 隐式调用 * operator@(aa,bb) 显式调用 (3)说明: * 有时在函数返回的时候,可以直接调用类的构造函数来生成一个临时对象,而不对该对象进行命名 c++ complex operator_(complex&a,complex &b) { complex temp; temp.real=a.real+.real; temp.imag=a.imag+b.imag: return temp; //建立了一个临时对象,他没有对象名,是一个无名对象。在建立临时对象过程在调用构造函数,用return语句将此临时对象作为函数返回值。 } * 有的c++系统提供的不带后缀的.h头文件不支持友元运算符重载函数,在visula c++ 6.0会编译出错,这时可采用带后缀的.h头文件。单目运算符重载: (1) 单目运算符只有一个操作数,例如:-a,&b,!c,++p 用友元函数重载单目运算符时,需要一个显式的操作数。 (2) 实例class coord { int x,y; public: coord(int i=0,int j=0); void print(); friend coord operator++(coord op); }; coord::coord(int i,int j) { x=i; y=j; } coord operator++(coord op) { ++op.x; ++op.y; return op; } void coord::print() { cout<<"x"<<"y"< int main() { coord ob(10,20); ob.print(): operator++(ob);//显式调用 ob.print(): ++ob;//隐式调用 ob.print(): return 0; } 运行结果为: 本例使用对象作为运算符函数的形参,是传值调用, 对象ob不随着op变化,应该使用对象引用作为形参,即传址调用 (3)调用方式: operator@(aa)//显式 @aa //隐式 (4)说明: 运算符重载函数operator可以返回任何类型,甚至可以是void类型 但通常返回类型与他所操作的类的类型相同 有的运算符不能定义为友元运算符重载函数,如赋值运算符=,下表运算符【】,函数调用运算符()等。 成员运算符重载函数 定义成员运算符重载函数的语法形式: (1)在类的内部定义,定义成员运算符函数重载函数的格式:函数类型 operator运算符(形参表) { } (2)成员运算符重载函数也可以在类中声明成员函数的原型,在类外定义。//在类的内部定义,定义成员运算符重载函数的格式如下: class X { .... 函数类型 operator运算符(形参表); }; //在类外定义,定义成员运算符重载函数格式如下: 函数类型 X::operator运算符(形参表) { 函数体 } 在成员运算符重载函数的形参表中, 若运算符是单目的,则参数表为空。若运算符是双目的,则参数表中有一个参数。 双目运算符重载 对于双目运算符而言,成员运算符函数的参数表中仅有一个参数: * 参数表中的参数为右操作数 * 当前对象,左操作数,它是通过this指针隐含的传递给函数的。 complex complex::operator+(complex c) { complex temp; temp.real=this->real+c.real;//隐含的this temp.imag=this->real+c.imag; return temp; } A3=A1.operator+(A2);//显式调用 A2为右操作数 A3=A1+A2;//隐式调用 //两个语句执行结果相同 调用格式: aa@bb; aa.operator@(bb); 单目操作符重载: 成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。 class coord { int x,y; public: coord(int i=0,int j=0); void print(): coord operator++()://参数表中没有参数,当前对象作为运算符的一个操作数 }; void coord::print() { cout< } coord::coordoperator++() { ++x; ++y; return *this; } 调用方式: aa.operator@();//显式调用 @aa;//隐式调用 特殊说明 双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但有一种情况,必须使用友元函数 。 class nclass { int a,b; public: nclass(int m=0,int n=0); nclass operator+(int x); void show(): }; nclass nclass:: operator+(int x)//x为整数 { nclass temp; temp.a=a+x.a;//当前对象.a + 整数x temp.b=b+a.b;//当前对象.b + 整数x return temp; } nclass:: nclass (int x,int y) { a=x; b=y; } void nclass::show() {