double fun::operator()(double x,double y,double z) const {
return (x*x+y*y)*z;
}
void main() {
fun f;
cout<<f(3.0,2.0,5.0)<<endl;
}
程序运行结果为:
65
执行 f(3.0,2.0,5.0)时,对象 f 是函数调用运算符“()”的左操作数,而 3.0、2.0、5.0 构成 实参表;其左操作数是 fun 类的对象 f,它将执行对 fun 类的重载函数的调用。
6.4 类型转换
我们在使用重载的运算符时,往往需要在自定义的数据类型和系统预定义的数据类型之 间进行转换,或者需要在不同的自定义数据类型之间进行转换。本节介绍 C++中数据类型的 转换。
6.4.1 系统预定义类型间的转换
对于系统预定义的数据类型,C++提供了两种类型转换方式,即隐式类型转换(或称标准 类型转换)和显式类型转换。
(1)隐式类型转换
隐式类型转换主要遵循以下规则:
字符或 short 类型变量与 int 类型变量进行运算时,将字符或 short 类型转换成 int 类型;
float型数据在运算时一律转换为双精度(double)型,以提高运算精度(同属于实型);
在赋值表达式 A=B 中,赋值运算符右端 B 的值需转换为 A 类型后再进行赋值;
当两个操作对象类型不一致时,在算术运算前,级别低的自动转换为级别高的类型。
(2)显式类型转换
强制转换法 (类型名)表达式 例如:
int i,j;
cout<<(float)(i+j);
函数法
类型名(表达式)
例如:
int i,j;
cout<<float (i+j)
例 6.17 系统预定义类型间转换。
#include<iostream.h>
void main() {
int a=5,sum;
double b=5.55;
sum=a+b;//---①
cout<<"隐式转换:a+b="<<sum<<endl;
sum=(int)(a+b);//---② sum=int(a+b); //---③
cout<<"显式转换:a+b="<<sum<<endl;
}
程序运行结果为:
隐式转换:a+b=10 显式转换:a+b=10
上述代码中的①就是含有隐式类型转换的表达式,在进行“a+b”时,编译系统先将 a 的 值 5 转换为双精度 double,然后和 b 相加得到 10.55,在向整型变量 sum 赋值时,将 10.55 转 换为整型数 10,赋值给变量 sum。这种转换由 C++编译系统自动完成,不需要用户干预。而 上例中的②和③中则涉及到了显式类型转换,它们都是把 a+b 所得结果的值强制转换为整型 数。只是②式是 C 语言中用到的形式“(类型名)表达式”,而③式是 C++中采用的形式“类型 名(表达式)”。
6.4.2 类类型与系统预定义类型间的转换
对于用户自己定义的类类型而言,编译系统并不知道怎样进行转换。解决这个问题的关键 是让编译系统知道怎样去进行这些转换,需要定义专门的函数来处理。C++中提供了如下两种 方法:
通过转换构造函数进行类型转换;
通过类型转换函数进行类型转换。
1.通过转换构造函数进行类型转换
转换构造函数(conversion constructor function)的作用是将一个其他类型的数据转换成一 个类的对象。主要有以下几种构造函数:
(1)默认构造函数。以 Complex 类为例,函数原型的形式为:
Complex( ); //没有参数
(2)用于初始化的构造函数。函数原型的形式为:
Complex(double r,double i); //形参列表中一般有两个以上参数
(3)用于复制对象的拷贝构造函数。函数原型的形式为:
Complex (Complex &c); //形参是本类对象的引用
(4)再介绍一种新的构造函数——转换构造函数,转换构造函数只有一个形参,如:
Complex(double r) {real=r;imag=0;}
其作用是将 double 型的参数 r 转换成 Complex 类的对象,将 r 作为复数的实部,虚部为 0。
用户可以根据需要定义转换构造函数,在函数体中告诉编译系统怎样去进行转换。
毫无疑问转换构造函数就是构造函数的一种,只不过它具有类型转换的作用。回顾下例 6.1中两个复数(sum=com1+com2)相加的实例,现在如果想要实现 sum=com1+5.5 该怎么办,
也许首先会想到再定义一个关于复数加双精度数的运算符重载函数,这样做的确可以。另外还 可以定义一个转换构造函数来解决上述问题。可对 Comlex 类(复数类)进行如下改造。
例 6.18 使用转换构造函数完成双精度数到复数的转换。
#include<iostream.h>
class Complex //复数类 {
private://私有
double real;//实数 double imag;//虚数 public:
Complex(double real,double imag) {
this->real=real;
this->imag=imag;
}
Complex(double d=0.0)//转换构造函数 {
real=d;//实数取 double 类型的值 imag=0;//虚数取 0
}
Complex operator+(Complex com1);
void showComplex();
};
Complex Complex::operator+(Complex com1) {
return Complex(real+com1.real,imag+com1.imag);
}
void Complex::showComplex() {
cout<<real;
if(imag>0) cout<<"+";
if(imag!=0)
cout<<imag<<"i"<<endl;
else
cout<<endl;
} int main() {
Complex com(10,10),sum;
sum=com+Complex(5.5);//①
sum.showComplex();//输出运算结果 sum=com+6.6; //②
sum.showComplex();//输出运算结果 sum=5.5; //③
sum.showComplex();//输出运算结果 return 0;
}
程序运行结果为:
15.5+10i 16.6+10i 5.5
main()函数中的语句①显式地调用转换构造函数 Complex(5.5),将 double 类型的 5.5 转换 为无名的 Complex 类的临时对象(5.5+0i),然后执行两个 Complex 类(复数类)对象相加的 运算符重载函数。语句②隐式地调用转换构造函数 Complex(6.6),将 double 类型的 6.6 转换为 无名的 Complex 类的临时对象(6.6+0i),然后执行两个 Complex 类(复数类)对象相加的运 算符重载函数。语句③隐式调用 Complex(5.5),将 double 类型的 5.5 转换为无名的 Complex 类的临时对象(5.5+0i),然后调用缺省的赋值运算符函数完成对 sum 的赋值。所以说一般的 转换构造函数的定义形式如下:
类名(待转换类型) {
函数体;
} 说明:
(1)转换构造函数只有一个形参。
(2)在类体中,可以有转换构造函数,也可以没有转换构造函数,视需要而定。
(3)当几种构造函数同时出现在同一个类中,它们是构造函数的重载。编译系统会根据 建立对象时给出的实参的个数与类型来选择与之匹配的构造函数。
(4)转换构造函数不仅可以将系统预定义类型的数据转换成类对象,也可以将另一个类 的对象转换成转换构造函数所在类的对象。
例如,将一个学生类对象转换为教师类对象,可以在 Teacher 类中定义出下面的转换 构造函数:
Teacher(Student &s) {
num=s.num;
strcpy(name,s.name);
sex=s.sex;
}
但应注意,对象 s 中 num、name 和 sex 必须是公有成员,否则不能在类外被访问。
2.通过类型转换函数进行类型转换
转换构造函数可以把系统预定义类型转化为自定义类的对象,但是却不能把类的对象转 换为基本数据类型。比如,不能将 Complex 类(复数类)的对象转换成 double 类型数据。在 C++中可用类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是
将一个类的对象转换成另一类型的数据,定义类型转换函数的一般形式为:
class 源类类名{
//…
operator 目标类型( ) {
//…
return 目标类型的数据;
} //…
};
说明:
(1)源类类名为要转换的源类类型,目标类型为要转换成的类型,它既可以是自定义的 类型也可以是系统预定义类型。
(2)类型转换函数的函数名前不能指定返回类型,且没有参数。从函数的形式看,它与 运算符重载函数相似,都是用 operator 开头,只是被重载的是类型名。
(3)类型转换函数只能定义为一个类的成员函数,因为转换的主体是本类对象。不能为 友元函数或普通函数。
(4)类型转换函数中必须有“return 目标类型的数据;”的语句,即必须回传目标类型数 据作为函数的返回值。
(5)在类中可以有多个类型转换函数,C++编译器将根据操作数的类型自动地选择一个 合适的类型转换函数与之匹配。
例 6.19 类型转换函数显式调用举例。
#include<iostream.h>
class Complex{
public:
Complex(float r=0,float i=0) {
real=r;
imag=i;
cout<<"Complex class Constructing...\n";
}
operator float() {
cout<<"Complex changed to float...\n";
return real;
}
operator int() {
cout<<"Complex changed to int...\n";
return int(real);
}
void print()
{ cout<<'('<<real<<','<<imag<<')'<<endl;}
private:
float real,imag;
};
int main() {
Complex a(1.1,3.3);
a.print();
cout<<float(a)*0.5<<endl;
Complex b(2.5,5.5);
b.print();
cout<<int(b)*2<<endl;
return 0;
}
程序运行结果为:
Complex class Constructing...
(1.1,3.3)
Complex changed to float...
0.55
Complex class Constructing...
(2.5,5.5)
Complex changed to int...
4
上例中两次调用了类型转换函数。第一次采用显式调用,将类对象 a 转换成 float 类型。
第二次也是显式调用,将类对象 b 转换为 int 类型。类型转换函数的调用分为显式转换与隐式 转换两种形式,下面通过例 6.20 来说明如何进行隐式转换。
例 6.20 类型转换函数隐式调用的举例。
#include<iostream.h>
class Complex{
public:
Complex(int r,int i) {
real=r;
imag=i;
cout<<"Complex class Constructing...\n";
}
Complex(int i=0) //转换构造函数 { real=imag=i/2;}
operator int() //类型转换函数 {
cout<<"Complex changed to int...\n";
return real+imag;
} void print()
{ cout<<"real:"<<real<<"\t"<<"imag:"<<imag<<endl;}
private:
int real,imag;
};
int main() {
Complex c1(1,2),c2(3,4);
c1.print();
c2.print();
Complex c3;
c3=c1+c2;
c3.print();
}
程序运行结果为:
Complex class Constructing...
Complex class Constructing...
real:1 imag:2 real:3 imag:4
Complex changed to int...
Complex changed to int...
real:5 imag:5
上例中没有在类中重载运算符“+”,为何 c3=c1+c2 成立呢?原因在于 C++自动进行了隐 式转换,将 c1 与 c2 分别都转换成 int 型,然后调用转换构造函数将整型数据转换为 complex 类。这里类型转换函数和转换构造函数构成了互逆操作,转换构造函数 Complex(int)将一个整 型转换成一个 Complex 类型,而类型转换函数 Complex::operator int()将 Complex 类型转换成 整型。