重载
- 重载单目运算符
单目运算符只有一个操作数(如 !a, -b, ++i, - -j 等),因此重载函数只有一个参数,如果重载函数为成员函数,还可以省约此参数。
例:将“-”重载成友元函数。
单目运算符一般重载为成员函数
#include <iostream.h>
class complex
{ private:
double real,image;
public:
complex(double r=0,double i=0):real(r),image(i){};
void show()
{ cout<<real;
if (image>0) cout<<'+'<<image<<'i'<<endl;
else
cout<<image<<'i'<<endl; }
friend complex operator-(complex &com);
};
complex operator-(complex &com)
{ return complex(-com.real,-com.image); }
void main()
{ complex ob1(1,-4.5),ob2;
ob2=-ob1;
ob2.show();
}
例4.5: “++”重载成员函数。
对 Time类,模拟秒表,满60秒进一分钟,秒又从0开始计。输出分、秒。
#include <iostream.h> // “++”重载
class Time
{public:
Time(){minute=0;sec=0;}
Time(int m,int s):minute(m),sec(s){}
Time operator++(); // 重载++运算符
void display(){cout<<minute<<":"<<sec<<endl;}
private:
int minute; int sec; };
Time Time::operator++()
{ if(++sec>=60)
{sec-=60; ++minute;}
return *this; // 返回当前对象值
}
int main()
{ Time time1(34,0);
for (int i=0;i<65;i++)
{++time1; time1.display();}
return 0; }
例4.6: 在4.5基础上增加后置自增运算符 “++”重载。
#include <iostream.h>
class Time
{public:
Time(){minute=0;sec=0;}
Time(int m,int s):minute(m),sec(s){}
Time operator++(); //声明前置自增++重载函数
Time operator++(int); //声明后置自增++重载
void display()
{cout<<minute<<":"<<sec<<endl;}
private: int minute, sec;
};
区别:前置++ 是先自加,返回是修改后的对象本身。
后置++ 是,返回是自加前对象,然后自加。
注意:后置++ 的int参数只是与前置++函数有所区别,没有任何作用。
Time Time::operator++()
{ if(++sec>=60)
{sec-=60; ++minute;}
return *this;}
Time Time::operator++(int)
{Time temp(*this);
//保存当前对象
sec++;
if (sec>=60) {sec-=60; ++minute;} return temp;}
int main()
{Time time1(34,59),time2;
cout<<" time1 : "; time1.display();
++time1;
cout<<"++time1: ";
time1.display(); time2=time1++;
cout<<"time1++: ";
time1.display();
cout<<" time2 : ";
time2.display(); return 0;
}
2、 重载流插入和流提取运算符
C++的流插入运算符“<<”和流提取运算符“>>”是在类库中提供的。
cin是istream类的对象,cout是ostream 类的对象。
在类库提供的头文件中已经对“<<”和“>>”进行了重载(整型、实型等的输入和输出)。
凡是用 cout<< 和 cin>> 进行输入输出的,都要将:
#include
include
#include <iostream.h>
class complex
{public:
friend ostream & operator << (ostream&, complex&);
friend istream & operator >> (istream&, complex&);
private: double real, image;
} ;
ostream& operator << (ostream& output, complex& c)
{output<<"("<<c.real<<"+" <<c.image<<"i)"<<endl;
return output; }
istream& operator >> (istream& input, complex& c)
{cout<<" 请输入复数的实数部分和虚数部分 "<<endl;
input>>c.real>>c. image;
return input; }
void main( )
{ complex c1, c2; //定义复数对象
cin>>c1>>c2; // 使用本程序重载定义的功能
cout<<"c1="<<c1<<endl; // 使用本程序重载定义的功能
cout<<"c2="<<c2<<endl;
}
3、 不同类型数据间的转换
A、标准类型数据间的转换
1)C++支持不同类型数据间的自动转换。— 隐式转换
例如:int i = 6;
i = 7.5 + i;
求解表达式时,编译系统先将整数6转换成double类型6.0,再与7.5相加,和为13.5,然后在赋给整数变量 i 之前,将13.5转换成整数13,并赋给变量 i 。
2) C++显式类型转换: 数据类型名 (数据)
注意:它与C语言格式不同,C语言是
(数据类型名) 数据
C++保留了C语言的格式,但提倡用C++的格式。
例如: int (13.6); // 结果等于13。
问题:用户自己定义的类对象能否转换成标准类型数据?一个类的对象能否转换成另外一个类的对象?
例如:复数类转换成整数或双精度数?
对于标准类型的转换,编译系统有规则,而对于用户自己声明的类型,就得让编译系统知道怎么进行转换。
构造函数:
默认构造函数:如complex ( );
用于初始化的构造函数:
如: complex (double r, double i)
B、转换构造函数:作用是将一个其它类型的数据转换成指定类的对象。
例如:
complex (double r) { real = r; image = 0; }
说明:作用是将double 型参数 r 转换成 complex 类的对象,将 r 作为复数的实部,虚部为0。
例如:已有转换构造函数:
complex (double r) { real = r; image = 0; }
则:complex c1(3.6);
// 建立c1对象,由于只有一个参数,调用转换构造函数
complex (13.6 );
// 建立无名对象,合法,但无法使用,此为类型转换
c1 = complex (13.6);
//合法,利用类型转换构造函数建立对象,并赋值给c1
#include <iostream.h>
class complex
{ private: double real,image;
public:
complex() { real = 0; image = 0; } // 普通构造函数
complex(double r) { real = r; image = 0; } // 转换构造函数
void show()
{ cout<<real;
if (image>=0) cout<<'+'<<image<<'i'<<endl;
else cout<<image<<'i'<<endl; }
};
void main()
{ complex c1(3.6); // 调用转换构造函数
c1.show();
complex c2; // 调用普通构造函数
c2.show();
c2= complex (10.6); // 调用转换构造函数生成对象并赋值给c2.
c2.show();
}
利用转换构造函数将指定数据类型转换成类对象的步骤如下:
①、声明一个类( 如complex );
②、在该类中定义一个转换构造函数(只有一个 参数),参数类型是待转换的类型。
③、以下形式进行类型转换:
类名(待转换类型的数据);
注意:转换构造函数只能有1个参数,若有多个参数则 不是转换构造函数。(多个参数转换哪个?)
C、类型转换函数—-类成员函数
类型转换函数的作用:将一个类的对象转换成另一类型的数据。省去了对不同的运算符一一重载的麻烦。
类型转换函数的格式:
operator 类型名( ) //将本类对象转换为指定类型
{ 实现转换的语句 }
例如:已经声明了一个complex类,可在类中定义类型转换函数:
operator double( ) // double类型重载后除了原有含义,也有
{ return real; } // 将complex对象转换成double类型的含义
注意:
1)类型转换函数使用operator关键字,因此也称为“类型转换运算符重载函数”。
2)类型转换函数只能是类成员函数,因为转换的主体是本类对象,不能作为友员函数或普通函数。
例4.9:类型转换函数的应用
#include <iostream>
using namespace std;
class Complex //类定义
{public:
Complex(){real=0;imag=0;}
Complex(double r,double i)
{real=r;imag=i;}
operator double()
//类型转换函数
{return real;}
private:
double real, imag;
};
int main()
{Complex c1(3,4),c2(5,-10),c3;
double d;
d=2.5+c1; //自动调用类型转换函数
cout<<d<<endl;
cout<<c1<<endl;
//自动调用类型转换函数
cout<<c2<<endl;
//自动调用类型转换函数
return 0;
}
3、不同类型数据间的转换
转换构造函数和类型转换函数有一个共同的特点:在需要的时候,系统会自动调用这些函数。
例如:若已定义double变量到 d1、d2,complex对象 c1,c2。且类中已定义了类型转换函数,设程序有以下表达式:
d1 = d2 + c1
编译系统发现“+”左侧的d2是double型,右侧c1是 complex对象,如果没有对“+”重载,就会检测有无类型转换函数,结果发现对double的重载函数,就调用该函数,将complex对象c1转换成double型数据,建立了一个临时的double型变量,并与d2相加,最后将double 型和数赋给变量d1。
例4.10 运算符重载、转换构造函数的综合应用
#include <iostream.h>
class complex
{public:
complex( ){ real=0; image=0; }
complex (double r)//转换构造函数
{ real=r; image=0; }
complex (double r, double i)
{ real = r; image = i; }
friend complex operator +
(complex c1,complex c2);
operator double(){return real;}
// 此时 类型转换函数会产生二义性.
void display( );
private:
double real, image;
};
void complex::display( )
{ cout<<"("<<real<<","
<<image<<"i)"<<endl;
}
complex operator +(complex c1,
complex c2)
{ // 运算符重载为友元
return complex (c1.real+c2.real,
c1.image+c2.image);
}
void main( )
{ complex c1(3,4), c2(5,-10), c3;
c3 = c1+ 2.5; //
c3.display( );
}
3、 不同类型数据间的转换
程序分析:
1)如果没有定义转换构造函数,程序出错,因为即使重载运算符,也不能让complex对象与double数据相加。
2)定义了转换构造函数,也重载了“+”运算符,在处理c1+2.5时,编译系统解释为operator +(c1, 2.5),由于2.5不是complex 对象,系统先调用转换构造函数 complex(2.5),建立一个临时对象,其值为( 2.5 +0i )。表达式成为:
operator + (c1,complex(2.5))
// 两对象相加,结果赋给c3。