C++数据类型转换以及转换构造函数
标准数据类型之间的转换
在C++中,某些不同类型数据之间可以自动转换,例如
int i = 6; i = 7.5 + i;</div>
编译系统对 7.5是作为double型数处理的,在求解表达式时,先将6转换成double型,然后与7.5相加,得到和为13.5,在向整型变量i赋值时,将13.5转换为整数13,然后赋给i。这种转换是由C++编译系统自动完成的,用户不需干预。这种转换称为隐式类型转换。
C++还提供显式类型转换,程序人员在程序中指定将一种指定的数据转换成另一指定的类型,其形式为:
类型名(数据)</div>
如
int(89.5)</div>
其作用是将89.5转换为整型数89。
以前我们接触的是标准类型之间的转换,现在用户自己定义了类,就提出了一个问题:一个自定义类的对象能否转换成标准类型? 一个类的对象能否转换成另外一个类的对象?譬如,能否将一个复数类数据转换成整数或双精度数?能否将Date类的对象转换成Time类的对象?
对于标准类型的转换,编译系统有章可循,知道怎样进行转换。而对于用户自己声明的类型,编译系统并不知道怎样进行转换。解决这个问题的关键是让编译系统知道怎样去进行这些转换,需要定义专门的函数来处理。
转换构造函数
转换构造函数(conversion constructor function) 的作用是将一个其他类型的数据转换成一个类的对象。这里回顾一下以前学习过的几种构造函数:
1) 默认构造函数。以Complex类为例,函数原型的形式为:
Complex( ); //没有参数</div>
2) 用于初始化的构造函数。函数原型的形式为:
Complex(double r, double i); //形参表列中一般有两个以上参数</div>
3) 用于复制对象的复制构造函数。函数原型的形式为:
Complex (Complex &c); //形参是本类对象的引用</div>
现在介绍一种新的构造函数——转换构造函数。
转换构造函数只有一个形参,如
Complex(double r) {real=r;imag=0;}</div>
其作用是将double型的参数r转换成Complex类的对象,将r作为复数的实部,虚部为0。用户可以根据需要定义转换构造函数,在函数体中告诉编译系统怎样去进行转换。
在类体中,可以有转换构造函数,也可以没有转换构造函数,视需要而定。以上几种构造函数可以同时出现在同一个类中,它们是构造函数的重载。编译系统会根据建立对象时给出的实参的个数与类型选择形参与之匹配的构造函数。
假如在Complex类中定义了上面的构造函数,在Complex类的作用域中有以下声明语句:
Complex cl(3.5) ; //建立对象cl,由于只有一个参数,调用转换构造函数</div>
建立Comptex类对象cl,其real(实部)的值为3.5,imag(虚部)的值为0。它的作用就是将double型常数转换成一个名为cl的Complex类对象。也可以用声明语句建立一 个无名的Complex类对象。如
Complex(3.6) ; //用声明语句建立一个无名的对象,合法,但无法使用它</div>
可以在一个表达式中使用无名对象,如:
cl =Complex(3.6); //假设cl巳被定义为Complex类对象</div>
建立一个无名的Complex类对象,其值为(3.6+0i),然后将此无名对象的值賦给cl,cl 在赋值后的值是(3.6+0i)。
如果已对运算符“+”进行了重载,使之能进行两个Complex类对象的相加,若在程序中有以下表达式:
c = cl +2.5;</div>
编译出错,因为不能用运算符“+”将一个Comptex类对象和一个浮点数相加。可以先将 2.5转换为Complex类无名对象,然后相加:
c = cl + Complex (2.5); //合法</div>
请对比Complex(2.5)和int(2.5)。二者形式类似,int(2.5)是强制类型转换,将2.5转换为整数,int()是强制类型转换运算符。可以认为Complex(2.5)的作用也是强制类型 转换,将2.5转换为Complex类对象。
转换构造函数也是一种构造函数,它遵循构造函数的一般规则。通常把有一个参数的构造函数用作类型转换,所以,称为转换构造函数。其实,有一个参数的构造函数也可以不用作类型转换,如
Complex (double r){ cout<<r; } //这种用法毫无意义,没有人会这样用</div>
转换构造函数的函数体是根据需要由用户确定的,务必使其有实际意义。例如也可 以这样定义转换构造函数:
Complex(double r){ real =0; imag = r; }</div>
即实部为0,虚部为r。这并不违反语法,但没有人会这样做。应该符合习惯,合乎情理。
注意:转换构造函数只能有一个参数。如果有多个参数,就不是转换构造函数。原因是显然的,如果有多个参数的话,究竟是把哪个参数转换成Complex类的对象呢?
归纳起来,使用转换构造函数将一个指定的数据转换为类对象的方法如下:
1) 先声明一个类。
2) 在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。
3) 在该类的作用域内可以用以下形式进行类型转换:
类名(指定类型的数据)
就可以将指定类型的数据转换为此类的对象。
不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在的类对象。如可以将一个学生类对象转换为教师类对象,可以在Teacher类中写出下面的转换构造函数:
Teacher(Student& s){ num=s.num;strcpy(name, s.name);sex=s.sex; }</div>
但应注意,对象s中的num,name,sex必须是公用成员,否则不能被类外引用。
C++类型转换函数(类型转换运算符函数)
用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成double类型数据)。
C++提供类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:
operator double( ) { return real; }</div>
函数返回double型变量real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员real的值。请注意,函数名是operator double,这点是和运算符重载时的规律一致的(在定义运算符“+”的重载函数时,函数名是operator +)。
类型转换函数的一般形式为:
operator 类型名( ) { 实现转换的语句 }</div>
在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。
从函数形式可以看到,它与运算符重载函数相似,都是用关键字operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的double型数据,而且还会把Complex类对象作为double型数据处理。
那么程序中的Complex类对具有双重身份,既是Complex类对象,又可作为double类型数据。Complex类对象只有在需要时才进行转换,要根据表达式的上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。
[例] 使用类型转换函数的简单例子。
#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; double imag; }; int main( ) { Complex c1(3,4),c2(5,-10),c3; double d; d=2.5+c1;//要求将一