运算符重载:复杂数据类型按照常规运算方式处理
不能重载的算符 :
- .
- ::
- .*
- ?:
- sizeof
重载运算符的限制
重载运算符函数可以对运算符作出新的解释,但原有基本语义不变:
- 不改变运算符的优先级
- 不改变运算符的结合性
- 不改变运算符所需要的操作数
- 不能创建新的运算符
运算符函数可以重载为成员函数或友元函数
一元运算符:
Object op 或 op Object
- 重载为成员函数,解释为:
Object . operator op ()
操作数由对象Object通过this指针隐含传递 - 重载为友元函数,解释为:
operator op (Object)
操作数由参数表的参数Object提供
二元运算符
ObjectL op ObjectR
- 重载为成员函数,解释为:
ObjectL . operator op ( ObjectR )
左操作数由ObjectL通过this指针传递,右操作数由参数ObjectR传递 - 重载为友元函数,解释为:
operator op ( ObjectL, ObjectR )
左右操作数都由参数传递
用成员函数重载运算符
成员运算符函数的原型在类的内部声明:
class X {
//…
返回类型 operator运算符(形参表);
//…
}
在类外定义成员运算符函数:
返回类型 X::operator运算符(形参表)
{
函数体
}
双目运算符重载为成员函数:
对双目运算符而言,成员运算符函数的形参表中仅有一个参数,它作为运算符的右操作数,此时当前对象作为运算符的左操作数,它是通过this指针隐含地传递给函数的。
复数加:
#include <iostream.h>
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;
};
void Complex::display( ){
cout<<"("<<real<<","<<imag<<"i)"<<endl;}
Complex Complex:: operator + (Complex &c2) {
return Complex(real+c2.real, imag+c2.imag);}
int main( ){
Complex c1(3,4),c2(5,-10),c3;
c3=c1+c2;//相当于c3=c1.operator +(c2)
cout<<"c1=";c1.display( );
cout<<"c2=";c2.display( );
cout<<"c1+c2 ="; c3.display( );
return 0;
}
注:
- 对象做形参以引用形式出现,加const限定只用其值不改变;
- 对象做参数,一般用引用方式传参;
- display函数所有输出。
单目运算符重载为成员函数
对单目运算符而言,成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。
时间加:
class Time
{
public:
Time( ){minute=0;sec=0;}
Time(int m,int s):minute(m),sec(s){ }
Time operator++( ); //声明前置自增运算符“++”重载函数
Time operator++(int); //声明后置自增运算符“++”重载函数
private:
int minute;
int sec;
};
Time Time∷operator++( ) //定义前置自增运算符“++”重载函数
{
if(sec++>=60) {
sec-=60; //满60秒进1分钟
minute ++;
}
return *this; //返回当前对象值
}
Time Time∷operator++(int) //定义后置自增运算符“++”重载函数
{
Time temp(*this);
sec++;
if(sec>=60) {
sec-=60;
++minute;
}
return temp; //返回的是自加前的对象
}
后置运算临时加形参,是普通数据,不是当前对象,为了区分前置后置。
后置一般给一个虚拟形参,类型不能是类类型,简单数据类型即可
用友元函数重载
友元函数重载运算符常用于运算符的左右操作数类型不同的情况
在第一个参数需要隐式转换的情形下,使用友元函数重载运算符是正确的选择
友元函数没有 this 指针,所需操作数都必须在参数表显式声明,很容易实现类型的隐式转换
C++中不能用友元函数重载的运算符有
= () [] ->
复数运算 :
#include<iostream>
using namespace std;
class Complex
{ public:
Complex( double r =0, double i =0 ) { Real = r ; Image = i ; }
Complex(int a) { Real = a ; Image = 0 ; }
void print() const ;
friend Complex operator+ ( const Complex & c1, const Complex & c2 ) ;
friend Complex operator- ( const Complex & c1, const Complex & c2 ) ;
friend Complex operator- ( const Complex & c ) ;
private:
double Real, Image ;
};
Complex operator + ( const Complex & c1, const Complex & c2 )
{ double r = c1.Real + c2.Real ; double i = c1.Image+c2.Image ;
return Complex ( r, i ) ;
}
Complex operator - ( const Complex & c1, const Complex & c2 )
{ double r = c1.Real - c2.Real ; double i = c1.Image - c2.Image ;
return Complex ( r, i ) ;
}
Complex operator- ( const Complex & c )
{ return Complex ( -c.Real, - c.Image ) ; }
void Complex :: print() const
{ cout << '(' << Real << " , " << Image << ')' << endl ; }
形参是复杂数据类型用引用方式传参
引用放丢失,const防改变
成员运算符函数与友元运算符函数的比较
(1) 成员运算符函数比友元运算符函数少带一个参数(后置的++、–需要增加一个形参)。
(2) 双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但当操作数类型不相同时,必须使用友元函数。
重载赋值运算符:
赋值运算符重载用于对象数据的复制
operator= 必须重载为成员函数
重载函数原型为:
类名 & 类名 :: operator= ( 类名 ) ;
定义Name类的重载赋值函数 :
#include<iostream>
#include<cstring>
using namespace std;
class Name
{ public :
Name ( char *pN ) ;
Name( const Name & ) ; //复制构造函数
Name& operator=( const Name& ) ; // 重载赋值运算符
~ Name() ;
protected :
char *pName ;
int size ;
} ;
int main()
{ Name Obj1( "ZhangSan" ) ;
Name Obj2 = Obj1 ; // 调用复制构造函数
Name Obj3( "NoName" ) ;
Obj3 = Obj2 = Obj1 ; // 调用重载赋值运算符函数
}
对象之间复制,不调用复制构造函数;
复制构造函数在定义对象的时候起作用。
深复制目的:让当前对象拥有自己的资源
重载下标运算符 []
[] 运算符用于访问数据对象的元素
重载格式 类型 类 :: operator[] ( 类型 ) ;
#include<iostream>
using namespace std;
class vector
{ public :
vector ( int n ) { v = new int [ n ] ; size = n ; }
~ vector ( ) { delete [ ] v ; size = 0 ; }
int & operator [ ] ( int i ) { return v [ i ] ; }
private :
int * v ; int size ;
};
int main ( )
{ vector a ( 5 ) ;
a [ 2 ] = 12 ;
cout << a [ 2 ] << endl ;
}
重载函数调用符 ()
() 运算符用于函数调用
重载格式 类型 类 :: operator() ( 参数表 ) ;
#include
using namespace std ;
class F
{ public :
double operator ( ) ( double x , double y ) ;
} ;
double F :: operator ( ) ( double x , double y )
{ return x * x + y * y ; }
int main ( )
{ F f ;
cout << f ( 5.2 , 2.5 ) << endl ;
}
函数调用:
可以用函数形式描述
类对象来写
宏定义写
重载流插入和流提取运算符
istream 和 ostream 是 C++ 的预定义流类
cin 是 istream 的对象,cout 是 ostream 的对象
运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
用友元函数重载 << 和 >> ,输出和输入用户自定义的数据类型
重载输出运算符“<<”(只能被重载成友元函数,不能重载成成员函数)
ostream& operator<<(ostream& out,class_name& obj)
{
out<<obj.item1;
out<<obj.item2;
.. .
out<<obj.itemn;
return out;
}
重载输入运算符“>>” (只能被重载成友元函数)
istream& operator>>(istream& in,class_name& obj)
{
in>>obj.item1;
in>>obj.item2;
. . .
in>>obj.itemn;
return in;
}
在重载输入输出流时,可加入判断性语句,做合法性检测