c++笔记(7):运算符重载、类中数据类型的转换

1.

运算符重载:

重载运算符函数可以对运算符作出新的解释,但原有基本语义不变。是一种特殊的成员函数或友元函数
不改变运算符的优先级
不改变运算符的结合性
不改变运算符所需要的操作数 
不能创建新的运算符
语法形式为:
类型   类名  ::  operator  op ( 参数表 )
{
     // 相对于该类定义的操作,一个运算符被重载后,原有意义没有失去,只是定义了相对一特定类的一个新运算符
}
#include<iostream>
#include<cstdlib>
using namespace std;
class Calculator
{ public:
    Calculator() { value = 0 ; } ;//构造函数初始化
    void operator ++ () ;//重载了运算符++
    void operator -- () ; //重载了运算符--
    unsigned int operator() () ;//重载了运算符()
  private:
    unsigned int value;
}; 
int main()
{ Calculator Counter ;
   int i ;
   for( i = 0 ; i < 5 ; i ++ )
      { ++ Counter;//相当于Counter.operator++()
         cout << "\n Counter = " << Counter() ;
      }
   for( i = 0 ; i <= 5 ; i ++ )
      { -- Counter;//相当于Counter.operator--()
         cout << "\n Counter = " << Counter() ;//相当于Counter.operator++()()
      }
} 
void Calculator::operator ++ ()
{ if ( value < 65535 ) value ++ ;
  else
    { cout << "\nData overflow !" << endl ;
      exit( 0 ) ;//退出
    }
} 
void Calculator::operator --()
{ if ( value > 0 ) value -- ;
  else
    { cout << "\n Data overflow !" << endl ;
      exit( 0 ) ;//退出
    }
}
unsigned int Calculator::operator() ()
{ return value ; }

2.

用成员函数或友元函数重载运算符:

运算符函数可以重载为成员函数或友元函数 
关键区别在于成员函数具有 this 指针,友元函数没有this指针
不管是成员函数还是友元函数重载,运算符的使用方法相同

但传递参数的方式不同,实现代码不同,应用场合也不同 


一元运算符:Object op    或   op  Object

重载为成员函数,解释为:Object . operator op(),操作数由对象Object通过this指针隐含传递
重载为友元函数,解释为:operator op(Object),操作数由参数表的参数Object提供 

二元运算符:ObjectL opObjectR

重载为成员函数,解释为:ObjectL . operatorop(ObjectR ),左操作数由ObjectL通过this指针传递,右操作数由参数ObjectR传递
重载为友元函数,解释为:operator op(ObjectL, ObjectR ),左右操作数都由参数传递

当一元运算符的操作数,或者二元运算符的左操作数是类的对象时,定义重载运算符函数为成员函数
#include<iostream>//三维坐标的简单算术运算
using namespace std;
class TriCoor
{ public:
       TriCoor( int mx = 0, int my = 0, int mz = 0 ) { x = mx ; y = my ; z = mz ; }
       TriCoor operator + ( TriCoor t ) 
          { TriCoor temp ;
             temp.x = x+t.x ;  temp.y = y+t.y ;  temp.z = z+t.z ;
             return temp ;
          }
       TriCoor operator = ( TriCoor t ) { x = t.x ;  y = t.y ;  z = t.z ;  return * this ; }
       TriCoor operator ++ () { x ++ ;  y ++ ;  z ++ ;  return *this ; }
       void show() { cout << x << " , " << y << " , " << z << "\n"; }
       void assign( int mx, int my, int mz ) { x = mx;  y = my;  z = mz; }
  private:       int x, y, z ;	// 3_d coordinates
} ;
 
int main()
{ TriCoor a( 1, 2, 3 ), b, c ;
  a.show();  b.show();  c.show();
  for( int i = 0;  i < 5;  i ++ ) ++ b;      b.show() ;
  c.assign( 3, 3, 3 ) ;    c = a + b + c ;    c.show() ;
  c = b = a ;    c.show() ;
} 
3.
用友元函数重载:友元函数重载运算符常用于运算符的左右操作数类型不同的情况

在第一个参数需要隐式转换的情形下,使用友元函数重载运算符是正确的选择

例如:

class   Complex
{  int    Real ;	int    Imag ;
   public :
  Complex ( int a ) { Real = a ;   Imag = 0 ; }     
  Complex ( int  a  , int  b ) { Real = a ;   Imag = b ; }
  friend Complex  operator + ( Complex ) ;
}
int main()
{Complex  z ( 2 , 3 ) ,   k ( 3 , 4 ) ;
   z= z + 27 ; //正确,相当于z . operator + ( 27 ),调用构造函数将27 转换为 Complex 类常量   
   z = 27 + z ;//错误,27 不是Complex对象不能调用函数,成员函数重载的“ + ”运算符不支持交换律
}
友元函数没有 this 指针,所需操作数都必须在参数表显式声明

 C++中不能用友元函数重载的运算符有:=    ()    []    ->

#include<iostream>//复数运算
usingnamespace std;
classComplex
{public:
      Complex( double r =0, double i=0 ) { Real = r ;   Image = i; }
      Complex(inta) { Real = a ;  Image = 0 ; }
      void print() const;
      friend Complex operator+ ( constComplex & c1, const Complex & c2 ) ;
      friend Complex operator- ( constComplex & c1, const Complex & c2 ) ;
      friend Complex operator- ( constComplex & c ) ;
  private: 
      double Real, Image ;
};
Complexoperator + ( const Complex & c1, constComplex & c2 )
  { double r = c1.Real + c2.Real ;  double i= c1.Image+c2.Image ;
     return Complex ( r,  i) ;//构造返回对象
  }
Complexoperator - ( const Complex & c1, constComplex & c2 )
  { double r = c1.Real - c2.Real ;  double i= c1.Image - c2.Image ;
     return Complex ( r,  i) ;//构造返回对象
  }
Complexoperator- ( const Complex & c )
  { return Complex ( -c.Real,- c.Image ) ; }
voidComplex :: print() const
  { cout<< '(' << Real << " , " << Image << ')'<< endl ; }

int main()
{ Complex  c1( 2.5,3.7 ), c2( 4.2, 6.5 ) ;
   Complex c ;
   c = c1 - c2 ;	// operator-(c1,c2)
   c.print() ;
   c = 25 + c2 ;	// operator+(25,c2)
   c.print() ;
   c = c2 + 25 ;	// operator+(c2,52)
   c.print() ;
   c = - c1 ;	// operator-(c1)
   c.print() ;
}
使用友元重载运算符的讨论:

若一个运算符的操作需要修改类对象状态时,应该用成员函数重载;需要左值操作数的运算符(如 ++,--),若重载为友元函数时要用引用参数

TriCoor operator ++ ( TriCoor & opl )
   { opl . x ++;   opl . y ++;    opl . z ++;    return   opl ; }

 TriCoor ob ( 1 , 2 , 3 ) ;
ob ++; // 正确,也可以用指针不用引用参数,这种方式需要接收返回值

4.

重载"++","--":

前置方式: ++Aobject--Aobject

一元  成员函数  重载 A :: A operator++ () ; 解释为:Aobject . operator ++( ) ;

          友元函数  重载 friend A operator++ (A &) ; 解释为:operator ++( Aobject ) ;

后置方式: Aobject ++Aobject --

二元  成员函数  重载 A :: A  operator++ (int) ; 解释为: Aobject . operator ++( 0 ) ;//伪参数
          友元函数  重载: friend A 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; }
intmain( )
  { 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() ;
 }

#include<iostream>//友元函数重载++
using namespace std;
class increase
{public:
Increase ( ) { value=0; }
     void  display( )  const { cout<<value<<'\n'; } ;
     friend Increase  operator ++ ( Increase & ) ; 	 // 前置	
     friend Increase  operator ++ ( Increase &, int ) ;	 // 后置
  private:   unsigned  value ;
};
Increase  operator ++ ( Increase & a )
  { a.value ++ ;   return a ; }	
Increase  operator ++ ( Increase & a, int )//通过引用参数操作对象
 { Increase  temp(a);   a.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( ) ;
 }

5.

重载赋值运算符

赋值运算符重载用于对象数据的复制 
 operator= 必须重载为成员函数 
重载函数原型为:类名  &  类名  :: operator= ( 类名 ) ; 
#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 ;		// 调用重载赋值运算符函数 
}
Name::Name ( char  *pN )
 { cout <<" Constructing " << pN << endl ;
    pName = new char[ 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 = new char[ 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;
}

6.

重载运算符 [ ] 和 ( ):运算符 [] 和 () 是二元运算符 [ ] 和 ( ) 只能用成员函数重载,不能用友元函数重载 

[] 运算符用于访问数据对象的元素,重载格式类型  类 :: 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 ] ; }//返回元素的引用this-> v[i]
   private :       
       int * v ;       int size ;
};
int main ( )
{  vector  a ( 5 ) ;
    a [ 2 ] = 12 ;//返回引用的函数调用作左值	  
    cout << a [ 2 ] << endl ;
}

()运算符用于函数调用:重载格式 类型  类 :: operator()  ( 参数表  ) ;

#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 ;
}
7.

重载流插入和流提取运算符:istream 和 ostream 是 C++ 的预定义流类
cin 是 istream 的对象,cout 是 ostream 的对象
运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
用友元函数重载 << 和 >> ,输出和输入用户自定义的数据类型 

#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 ;//使用重载版本operator >> (cin , A)
  cout << "Output the elements of vector A :\n" ;
  cout << A ;//使用重载版本operator << (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 << " is outside !\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 ;
}
8.

数据类型转换在程序编译时或在程序运行实现
基本类型 ←→ 基本类型
基本类型 ←→ 类类型
类类型 ←→ 类类型
类对象的类型转换可由两种方式说明:构造函数 转换函数


构造函数进行类型转换:

class  X
{ // ……
  public :
      X ( int ) ;
      X ( const  char * , int = 0 ) ;
};
void  f ( X  arg ) ;
	:
   X  a = X( 1 ) ;		// a = 1,调用构造函数 X ( int ) 把 1 转换为类类型 X 后赋给对象 a,也称 X ( 1 ) 为 X 类的类型常量
   X  b = "Jessie" ;		// b = X ( "Jessie" , 0 ),调用构造函数X ( const  char * , int = 0 ) 把字符串转换为类类型 X 后赋给对象 b
   a = 2 ;			// a = X ( 2 ),隐式调用构造函数 X ( int ) 把 2 转换为类类型 X 后赋给对象
   f ( 3 ) ;			// f ( X ( 3 ) ),隐式调用构造函数 X ( int ) 对实参作类类型转换,然后做参数结合
   f ( 10 , 20 ) ;		// error当找不到匹配的构造函数时转换失败

类型转换函数进行类型转换:

带参数的构造函数不能把一个类类型转换成基本类型类类型转换函数是一种特殊的成员函数,提供类对象之间显式类型转换的机制

class  X
{  ……
   public :
        operator  int ( ) ;
   ……
} ;
void  f ( X  a )
{ int  i = int ( a ) ;
   i = ( int ) a ;
   i = a ;//a 是一个类对象,以上三种它们都用类型转换函数作类型转换,X :: operator  int (),对象 a可直接用在整型变量出现的地方
}
类型转换函数有两种使用方式:
    隐式使用 i = a ;
    显式使用 i = a . operator  int ( )// int ( a )      ( int ) a
使用不同函数作类型转换函数:
     int  i = a ; // 用类型转换函数进行转换

     X  i = a ; // 用构造函数进行转换

9.

#include<iostream>//有理数的计算
using namespace std;
class Rational
{
public:
	Rational();			//构造函数
	Rational(int n, int d = 1);		//构造函数
	Rational(double x);		//构造函数,double-->Rational
	operator double(); 		//类型转换函数,Rational-->double
	friend Rational operator+(const Rational &, const Rational &);
	friend ostream & operator<<(ostream &, const Rational &);
private:
	int  Numerator, Denominator;
};
int gcd(int a, int b);		//求最大公约数
int main()
{
	Rational a(2, 4);
	Rational b = 0.3;
	Rational c = a + b;
	cout << double(a) << " + " << double(b) << " = " << double(c) << endl;
		cout << a << " + " << b << " = " << c << endl;
	double x = b;
	c = x + 1 + 0.6;
	cout << x << " + " << 1 << " + " << 0.6 << " = " << double(c) << endl;
	cout << Rational(x) << " + " << Rational(1) << " + " << Rational(0.6) << " = " << c << endl;
	return 0;
}
Rational::Rational()	//构造等于0的对象
{
	Numerator = 0; Denominator = 0;
}
Rational::Rational(int n, int d)    //用分子、分母构造对象
{
	int g;
	if (d == 1)	               //分母等于1
	{
		Numerator = n;	 //分子
		Denominator = d;	 //分母
	}
	else		               //分母不等于1的有理数
	{
		g = gcd(n, d);	 //求分子、分母的最大公约数
		Numerator = n / g;       //约分
		Denominator = d / g;
	};
}
Rational::Rational(double x)	//用实数构造对象
{
	int a, b, g;
	a = int(x*1e5);		//分子
	b = int(1e5);		//分母
	g = gcd(a, b);		//求分子、分母的最大公约数
	Numerator = a / g;	//约分
	Denominator = b / g;
}
Rational::operator double() //类型转换函数,Rational-->double
{
	return double(Numerator) / double(Denominator);
}
//重载运算符 + 
Rational operator+(const Rational & r1, const Rational & r2)
{
	int n, d;
	n = r1.Numerator * r2.Denominator
		+ r1.Denominator * r2.Numerator;
	d = r1.Denominator * r2.Denominator;
	return  Rational(n, d);
}
//重载运算符 << 
ostream & operator<<(ostream & output, const Rational & x) {
	output << x.Numerator;
	if (x.Denominator != 1)
		output << "/" << x.Denominator;
	return output;
}
int gcd(int a, int b)	//求最大公约数
{
	int g;
	if (b == 0) g = a;
	else g = gcd(b, a%b);
	return g;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值