运算符重载
一 运算符重载的限制
有几种不能能重载运算符
,:: .* ?: sizeof
重载运算符函数 可以重新定义运算符函数,但是原有的基本语义不变:
1. 不改变运算符的优先级
2. 不改变运算符的结合性
3. 不改变运算符所需要的操作数
4. 不能创建新的运算符
5. 运算符函数可以重载为成员函数或者友元函数
语法形式
类型 类名::operator op(参数表)
{//结构体
}
类型 函数的返回类型
类名 要重载该运算符的类
Op 表示要重载的运算符
函数名 operator op 由关键字operator和被重载的运算符op组成。
参数表列出该运算符所需要的操作数。
有两个运算符系统提供默认版本:
赋值运算符“=” 系统默认重载为对象数据成员的复制。
地址运算符“&”系统默认重载为返回任何对象类的地址。
二 一元运算符
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
{//….
返回类型 Opeator 运算符(形参表);
//…
};
在类外定义成员函数的格式如下:
返回类型 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;
};
ComplexComplex:: operator + (Complex &c2) {
return Complex(real+c2.real, imag+c2.imag);}
void Complex::display( ){
cout<<"("<<real<<","<<imag<<"i)"<<endl;}
int main( ){
Complex c1(3,4),c2(5,-10),c3;
c3=c1+c2;
cout<<"c1=";c1.display( );
cout<<"c2=";c2.display( );
cout<<"c1+c2 =";c3.display();
return 0;
}
在成员函数中分为显示调用和隐式调用
一般而言,如果在类X中采用成员函数重载双目运算符@,成员运算符函数operator@ 所需的一个操作数由对象aa通过this指针隐含地传递,它的另一个操作数bb在参数表中显示,aa和bb是类X的两个对象,则以下两种函数调用方法是等价的:
aa @bb; // 隐式调用
aa.operator@(bb); // 显式调用
单目运算符重载为成员函数
对单目运算符而言,成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。
有一个Time类,包含数据成员minute(分)和sec(秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0开始算。要求输出分和秒的值。
class Time
{
public:
Time(){minute=0;sec=0;}
Time(intm,int s):minute(m),sec(s){ }// 分 秒
Timeoperator++( ); //声明前置自增运算符“++”重载函数
Timeoperator++(int); //声明后置自增运算符“++”重载函数
private:
intminute;
intsec;
};
Time Time∷operator++( ) //定义前置自增运算符“++”重载函数
{
if(++sec>=60) {
sec-=60; //满60秒进1分钟
++minute;
}
return*this; //返回当前对象值
}
Time Time∷operator++(int) //定义后置自增运算符“++”重载函数
{
Timetemp(*this);
sec++;
if(sec>=60) {
sec-=60;
++minute;
}
returntemp; //返回的是自加前的对象
}
一般而言,采用成员函数重载单目运算符时,以下两种方法是等价的:
@aa; // 隐式调用
aa.operator@(); // 显式调用
成员运算符函数operator @所需的一个操作数由对象aa通过this指针隐含地传递。因此,在它的参数表中没有参数。
当运算符左右操作的类型不同时,这是则使用友元函数进行重载。
class Complex
{ int Real ; int Imag ;
public :
Complex ( int a ) { Real = a ; Imag = 0 ; }
Complex ( int a ,int b ) { Real = a ; Imag = b ; }
Complex operator + ( Complex ) ;
…...
};
int f ( )
{Complex z ( 2 , 3 ) , k ( 3 , 4 ) ;
z = z + 27 ;//所对应的形式正确
z = 27 + z ;//所对应的形式错误
…...
}
Ø在第一个参数需要隐式转换的情形下,使用友元函数重载
运算符是正确的选择
Ø 友元函数没有 this 指针,所需操作数都必须在参数表显式
声明,很容易实现类型的隐式转换
Ø C++中不能用友元函数重载的运算符有
= () [] ->
成员函数与友元运算符函数的比较
(1) 成员运算符函数比友元运算符函数少带一个参数(后置的++、--需要增加一个形参)。
(2) 双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但当操作数类型不相同时,必须使用友元函数。
四 几个经典运算符重载
>>数学类中几个常用运算符重载的特点和应用
设 A Aobject ;
运算符 ++和 - - 有两种方式:
前置方式: ++Aobject --Aobject
成员函数 重载 A :: Aoperator++ () ;
解释为: Aobject. operator ++( ) ;
友元函数 重载 friendA operator++ (A &) ;
解释为: operator++( Aobject ) ;
后置方式:
成员函数 重载 A::A operator++ (int) ;
解释为: Aobject. operator ++( 0 ) ;
友元函数 重载: friendA operator++ (A &, int) ; 解释为: operator++(Aobject, 0)
例如:重载++的应用
#include<iostream>
using namespace std;
class Increase
{ public :
Increase () { value=0; }
void display( ) const{ cout<<value<<'\n'; } ;
Increase operator ++ ( ) ; //前置
Increase operator ++ ( int ) ; //后置
private: unsigned value ;
};
Increase Increase :: operator ++ ( )
{ value ++; return *this ; }
Increase Increase :: operator ++ ( int )
{ Increase temp; temp.value = value ++ ; return temp; }
int main( )
{Increase a , b , n ; int i;
for ( i = 0; i < 10 ; i ++ ) a = n ++ ;
cout<<"n= " ; n.display( ) ; cout <<"a= " ; a.display( ) ;
for ( i = 0; i < 10 ; i ++ ) b = ++ n ;
cout<< "n= " ;n.display( ) ;cout << "b= " ; b.display();
重载复制运算符
用于对象数据的复制
Operator=必须重载为成员函数
重载函数原型为:
类名 & 类名::operator=(类名);
#include<iostream>
#include<cstring>
using namespace std;
class Name
{ public :
Name (char *pN ) ;
Name( constName & ) ; //复制构造函数
Name&operator=( const Name& ) ; // 重载赋值运算符
~ Name() ;//析构函数
protected :
char *pName ;
int size ;
} ;
int main()
{ Name Obj1( "ZhangSan" ) ;
Name Obj2 =Obj1 ; // 调用复制构造函数
Name Obj3("NoName" ) ;
Obj3 = Obj2 =Obj1 ; // 调用重载赋值运算符函数
}
Name::Name ( char *pN )
{ cout<<" Constructing " << pN << endl ;
pName = newchar[ strlen( pN ) + 1 ] ;
if( pName !=0 ) strcpy( pName,pN ) ;
size =strlen( pN ) ;
}
Name::Name( const Name & Obj ) //复制构造函数
{ cout << " Copying " <<Obj.pName << " into its own block\n";
pName = new char[strlen( Obj.pName ) + 1 ] ;
if ( pName !=0 ) strcpy( pName, Obj.pName ) ;
size =Obj.size;
}
Name & Name::operator= ( const Name & Obj ) // 重载赋值运算符
{ delete []pName ;
pName = newchar[ strlen( Obj.pName ) + 1 ] ;//获取长度
if ( pName !=0 ) strcpy( pName , Obj.pName ) ;
size =Obj.size ;
return *this;
}
Name::~ Name()
{ cout << " Destructing " <<pName << endl ;
delete []pName ;
size = 0;
}
重载运算符【】和()
运算符【】和()时二元运算符
【】和()只能用成员函数重载,不能使用友元函数重载
1. 重载下标运算符【】
【】运算符用于访问数据对象的元素
重载格式 类型 类 ::operator[] ( 类型 ) ;
设 x 是类 X 的一个对象,则表达式
x [ y ]
可被解释为
x . operator [ ]( y )
#include<iostream>
using namespacestd;
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 ;
}
2. 重载函数调用运算符
()运算符用于函数调用
重载格式类型 类 :: operator() ( 参数表 ) ;
设 x 是类 X 的一个对象,则表达式 x ( arg1, arg2, … )可被解释为x . operator () (arg1, arg2, … )
#include <iostream>
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;
}
#include<iostream>
#include<cstdlib>
using namespace std;
class vector
{ public :
vector( int size =1 ) ; ~vector() ;
int & operator[] ( int i ) ;
friend ostream & operator << ( ostream & output , vector& ) ;
friend istream & operator >> ( istream & input, vector& ) ;
private :
int * v ; int len ;
};
int main(){
int k ; cout <<"Input the length of vector A :\n" ; cin >> k ;
vector A( k ) ; cout <<"Input the elements of vector A :\n" ;
cin >> A ; cout<< "Output the elements of vector A :\n" ;
cout << A ;
}
vector::vector( int size )
{ if (size <= 0 || size > 100 )
{cout << "The size of " << size << " is null!\n" ; exit( 0 ) ; }
v= new int[ size ] ; len = size ;
}
vector :: ~vector() { delete[] v ; len = 0 ; }
int & vector :: operator [] (int i )
{ if( i >=0 && i < len ) return v[ i ] ;
cout << "The subscript " << i << " isoutside !\n" ; exit( 0 ) ;
}
ostream & operator << (ostream & output, vector & ary )
{ for(int i = 0 ; i < ary.len ; i ++) output << ary[ i ] <<" " ;
output << endl ;
return output ;
}
istream & operator >> (istream & input, vector & ary )
{ for( int i = 0 ; i < ary.len ; i ++) input >> ary[ i ] ;
return input ;
}