函数类型 operator运算符名称(形参列表)
{ 对运算符的重载处理 }
函数名是由operator和运算符组成,如operator+意思是对运算符“+”重载。
重载运算符的函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也非类的友元函数的普通函数
对“+”运算符进行重载来实现两个Money类对象的加法运算。
#include <iostream>
using namespace std;
#include <string>
class Money
{public:
Money(int y = 0, int j = 0, int f = 0);
Money operator+(Money&);
void Display(string);
private:
int yuan, jiao,fen;
void Optimize( );};
void Money::Optimize( )
{ if ( fen >= 10 ){ jiao++; fen -=10; }
if ( jiao >= 10 ){ yuan++; jiao -=10; }}
Money:: Money(int y, int j, int f)
{ yuan = y; jiao = j; fen = f; Optimize( ); }
Money Money::operator+(Money &c2)
{ return Money ( yuan + c2.yuan, jiao + c2.jiao, fen + c2.fen ); }
void Money::Display(string str)
{ cout << str << " = " << yuan << "." << jiao << fen << "¥" << endl; }
int main( )
{ Money cost1(300, 5, 6), cost2(105, 7, 6), total1, total2;
total1 = cost1 + cost2
total2 = cost1.operator+(cost2);
total1.Display("total1 = cost1 + cost2");
total2.Display("total2 = cost1 + cost2");
return 0;}
在执行本句时,系统自动调用operator+函数,把cost1作为当前对象,把cost2作为实参,与形参进行虚实结合。 cost1+cost2解释为:cost1.operator+(cost2)
运算符名称 | 具体运算符 |
算术运算符 | +(加),-(减),*(乘),/(除),%(取模),++(自增),--(自减) |
位操作运算符 | &(按位与),~(按位取反),^(按位异或),|(按位或),<<(左移),>>(右移) |
逻辑运算符 | !(逻辑非),&&(逻辑与),||(逻辑或) |
比较运算符 | <(小于),>(大于),>=(大于等于),<=(小于等于),==(等于),!=(不等于) |
赋值运算符 | =,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>= |
其他运算符 | [](下标),()(函数调用),->(成员访问),,(逗号),new,delete,new[],delete[],->*(成员指针访问) |
运算符 | 功能 |
. | 成员访问运算符 |
.* | 成员指针访问运算符 |
:: | 域运算符 |
sizeof | 长度运算符 |
?: | 条件运算符 |
① 赋值运算符(=)可以用于每一个类对象,可以利用它在同类对象之间相互赋值。
② 地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
2、 运算符重载函数作为类的成员函数及友元函数class 类名{
…
返回类型 operator运算符(形参表);
…
};
返回类型 类名::operator运算符(形参表)
{
函数体
}
通过运算符重载为类的成员函数来实现两个有理数对象的加、减、乘和除运算。#include <math.h>
#include <iostream>
using namespace std;
class Rational //声明有理数类
{public:
Rational(int x=0,int y=1); //构造函数
void Print();
Rational operator+(Rational a);//重载运算符"+"
Rational operator-(Rational a);//重载运算符"-"
private:
int num,den;
void Optimi(); }; //优化有理数函数
void Rational::Optimi() //定义有理数优化函数
{ int gcd;
if(num==0) //若分子为0,则置分母为1后返回
{ den=1; return; }
gcd=(abs(num)>abs(den)?abs(num):abs(den));
if(gcd==0) return; //若为0,则返回
for(int i=gcd;i>1;i--) //用循环找最大公约数
if((num%i==0)&&(den%i==0)) break;
num/=i;//i为最大公约数,将分子、分母均整除它,重新赋值
den/=i;
//若分子和分母均为负数,则结果为正,所以均改为正
if(num<0&&den<0) { num= -num; den=-den; }
else if(num<0||den<0)
{//若分子和分母中只有一个为负数,则调整为分子取负,分母取正
num=-abs(num); den=abs(den);}
}
void Rational::Print() //输出有理数
{ cout<<num;
//当分子不为0且分母不为1时才显示"/分母“
if(num!=0&&den!=1) cout<<"/"<<den<<"\n";
else cout<<"\n";
}
Rational Rational::operator+(Rational a)
{//“+”运算符重载函数,根据前面所列的算法写出表达式
Rational r;
r.den=a.den*den;
r.num=a.num*den+a.den*num;
r.Optimi();
return r;
}
Rational Rational::operator-(Rational a)
{//“-”运算符重载函数,根据前面所列的算法写出表达式
Rational r;
r.den=a.den*den;
r.num=num*a.den-den*a.num;
r.Optimi();
return r;
}
int main()
{ Rational r1(3,14),r2(4,14),r3,r4;
r1.Print();
r2.Print();
r3=r1+r2; //使用重载了的运算符“+”
r3.Print();
r4=r1-r2; //使用重载了的运算符“-”
r4.Print();
return 0;
}
2.2 作为类的友元函数
class 类名{
…
friend返回类型operator运算符(形参表);
…
};
返回类型 operator运算符(形参表)
{
函数体
}
将运算符“+”和“-”重载为适合于有理数加减法,重载函数不作为成员函数,而放在类外,作为rational类的友元函数。
<pre name="code" class="cpp">#include<iostream>
using namespace std;
class Point
{public:
Point();
Point(int vx,int vy);
Point & operator++(); //重载前置自增为类的成员函数
Point operator++(int);//重载后置自增为类的成员函数
//重载前置自减为类的友元函数
friend Point& operator--( Point &p1);
//重载后置自减为类的友元函数
friend Point operator--( Point &p1,int);
void Display();
private:
int x,y;
};
Point::Point(){ x=0; y=0; }
Point::Point(int vx,int vy){ x=vx; y=vy; }
void Point::Display()
{ cout<<" ("<<x<<","<<y<<") "<<endl; }
Point & Point::operator++() //前置自增
{ if(x<640) x++; //不超过屏幕的横界
if(y<480) y++; //不超过屏幕的竖界
return *this;
}
Point Point::operator++(int) //后置自增
{//先将当前对象通过复制构造函数临时保存起来
Point temp(*this);
if(x<640) x++; //不超过屏幕的横界
if(y<480) y++; //不超过屏幕的竖界
return temp;
}
Point & operator--( Point &p) //前置自减
{ if(p.x>0) p.x--;
if(p.y>0) p.y--;
return p;
}
Point operator--( Point &p,int) //后置自减
{ //先将当前对象通过复制构造函数临时保存起来
Point temp(p);
if(p.x>0) p.x--;
if(p.y>0) p.y--;
return temp;
}
int main()
{ Point p1(10,10), p2(150,150), p3(20,20),
p4(160,160), p5;
cout<<"p1=";
p1.Display();
++p1; //测试前置自增
cout<<"++p1=";
p1.Display();
cout<<"p3=";
p3.Display();
p5=p3++;//测试后置自增
cout<<" p3++=";
p3.Display();
cout<<"p5=p3++=";
p5.Display();
cout<<"p2=";
p2.Display();
--p2; //测试前置自减
cout<<"--p2=";
p2.Display();
cout<<"p4=";
p4.Display();
p5=p4--; //测试后置自增
cout<<" p4--=";
p4.Display();
cout<<" p5= p4--=";
p5.Display();
return 0; }
X&X::operator=(constX& s)
{ //成员间赋值
}
obj1=obj2;
重载赋值运算符函数解决指针悬挂问题。
#include <iostream>
using namespace std;
#include <string>
#include <cassert>
class String //自定义字符串类
{public:
String( ); //默认构造函数
String(const char *src); //带参数的构造函数
~String( ); //析构函数
const char* ToString( ) const { return str; }
unsigned int Length( ) const { return len; }
String &operator=(const String &right);
//赋值运算符重载函数
private:
char *str;
unsigned int len; //存放字符串的长度
};
String:: String( ) //默认构造函数
{ len = 0;
str = new char[len+1];
str[0] = '\0';
}
String:: String(const char *src) //带参数的构造函数
{ len = strlen(src);
str = new char[len+1];
if (!str ) {
cerr << "Allocation Error!\n";
exit(1); }
strcpy(str, src);
}
String:: ~String( ) //析构函数
{ delete str;
str = NULL;
}
String &String:: operator=(const String &right)
//赋值运算符重载函数
{ if ( &right != this ) {
int length = right.Length( );
if ( len < length ) {
delete[] str;
str = new char[length+1];
assert(str != 0);
}
int i;
for (i = 0; right.str[i] != '\0'; i++ )
str[i] = right.str[i];
str[i] = '\0';
len = length;
}
return *this;
}
int main( )
{ String str1("Hi!"), str2("Hello!");
cout << "str1: " << str1.ToString( ) << endl;
cout << "str2: " << str2.ToString( ) << endl;
str1 = str2;
cout << "str1: " << str1.ToString( ) << endl;
return 0;
}
对“<<”和“>>”重载的函数形式如下:
ostream& operateor<< (ostream&,自定义类);
istream& operateor>> (istream&,自定义类);
在重载时要注意下面两点:
#include<iostream>
using namespace std;
class Timer
{ public:
Timer( );
Timer(int h, int m = 0);
friend Timer operator+( Timer &t1, Timer &t2);
friend Timer operator-(Timer &t1, Timer &t2);
friend ostream& operator<<(ostream &out,
Timer &t);
friend istream& operator>>(istream&in,
Timer &t);
private:
int hours;
int minutes;
};
Timer::Timer( )
{ hours = minutes = 0; }
Timer::Timer(int h, int m)
{ hours = h; minutes = m; }
Timer operator+( Timer &t1, Timer &t2)
{ Timer sum;
sum.minutes = t1.minutes + t2. minutes;
sum.hours = t1.hours + t2.hours + sum.minutes / 60;
sum.minutes %= 60;
return sum;}
Timer operator-(Timer &t1, Timer &t2)
{ Timer dif;
int x1, x2;
x1 = t2.hours*60 + t2.minutes;
x2 = t1.hours*60 + t1.minutes;
dif.minutes = (x2 - x1) % 60;
dif.hours = (x2 - x1) / 60;
return dif;
}
ostream& operator<<(ostream &out, Timer &t)
{ out << t.hours << "hours," << t.minutes << "minutes";
return out;
}
istream &operator>>(istream &in, Timer &t)
{ cout << "Input hours and minutes:";
in >> t.hours >> t.minutes;
return in;
}
int main( )
{ Timer t1, t2, t3, t4;
cin >> t1 >> t2;
cout << "t1 = " << t1 << "\n";
cout << "t2 = " << t2 << "\n";
t3 = t1 + t2;
cout << "t3 = t1 + t2 = " << t3 << "\n";
t4 = t1 - t2;
cout << "t4 = t1 - t2 = " << t4 << "\n";
return 0;}
程序运行结果如下:
Input hours and minutes:5 35
Input hours and minutes:6 22
t1= 5 hours, 35 minutes
t2= 6 hours, 22 minutes
t3= t1 + t2 = 11 hours, 57 minutes
t4= t1 - t2 = 0 hours, -47 minutes
4、转换构造函数C++提供显式类型转换,程序员在程序中将一种类型的数据转换为另一种指定类型的数据,其形式为:
类型名(表达式)
如: int(89.5)
其作用是将89.5转换为整型数89。
对于用户自己声明的类型,编译系统并不知道怎样进行转换。
解决这个问题的关键是让编译系统知道怎样去进行这些转换,需要定义专门的函数来处理。
通常 把只有一个形参的构造函数 ,称为转换构造函数。 编译器可以利用它执行自动类型转换, 将一个其他类型的数据 转换成 一个 转换构造函数所在类 的对象使用转换构造函数将一个指定类型的数据转换为类对象的方法如下:
(1)先声明一个类。
(2)在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。
(3)在该类的作用域内可以用以下形式进行类型转换:
类名(指定类型的数据)
就可以将指定类型的数据转换为此类的对象。
基于有理数类的包含转换构造函数和运算符重载的程序。
#include <iostream.h>
#include <math.h>
class Rational //声明有理数类
{ public:
Rational(); //无参构造函数
Rational(int x,int y); //有两个形参的构造函数
Rational(int x); //转换构造函数
void Print();
//重载函数作为友元函数
friend Rational operator+(Rational a, Rational b);
private:
int num,den;
void Optimi(); //有理数优化函数
};
//定义无参构造函数
Rational::Rational()
{ num=0;den=1; }
//定义有两个形参的构造函数
Rational::Rational(int x,int y)
{ num=x;den=y; }
//定义转换构造函数
Rational::Rational(int x)
{ num=x;den=1; }
void Rational::Print() //输出有理数
{ cout<<num;
//当分子不为0且分母不为1时才显示"/分母
if(num!=0&&den!=1) cout<<"/"<<den<<"\n";
else cout<<"\n"; }
//定义作为友元函数的重载函数
Rational operator+(Rational a, Rational b)
{ Rational r;
r.den=a.den*b.den;
r.num=a.num*b.den+a.den*b.num;
r.Optimi();
return r;}
void rational::Optimi() //定义有理数优化函数
{ … }
int main()
{ Rational r1(3,5),r2,r3;
int n=3;
r2=r1+n;
r2.Print();
r3=n+r1;
r3.Print();
return 0;
}
若有教师类Teacher,学生类Student ,可以定义下面的转换构造函数将Student 类转换为Teacher 类。
Teacher(Student &s)
{ num=s.num; strcpy(name,s.name); sex=s.sex; }
class类名{
…
operator <目的类型名>()
{
<函数体>
}
};
关于类型转换函数,有以下几点注意事项:
关于类型转换函数,有以下几点注意事项:
operator double( )
{ return real; }
( 5 ) 一个类可以定义多个类型转换函数 。 C++ 编译器将根据操作数的类型自动地选择一个合适的类型转换函数与之匹配。在可能出现二义性的情况下,应显式地使用类型转换函数进行类型转换class rational{ //声明有理数类
public:
rational(); //无参构造函数
rational(int x,int y); //有两个形参的构造函数
rational(int x); //转换构造函数
operator int(){ return num; } //类型转换函数
void print();
//重载函数作为友元函数
friend rational operator+(rational a, rational b); private:
int num,den;
void optimi();
};
int main()
{ rational r1(3,5),r2,r3;
int n=3;
r2=r1+n;
r2.print();
r3=n+r1;
r3.print();
return 0;}
转换构造函数和类型转换运算符函数有一个共同的功能:
当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。