9.7 类型转换

    前面已经对普通变量的类型转换进行了介绍,本节来讨论类对象和其他类型对象的转换,这些转换发生的场合同第2章中介绍的一样,主要有以下几种。

    ❑赋值转换

    ❑表达式中的转换

    ❑显式转换

    ❑函数调用,传递参数时的转换

    除了转换场合外,另一个问题就是转换方向,有“由其他类型向定义类的转换”和“由定义类向其他类型的转换”两种,下面分别展开讨论。

    9.7.1 由其他类型向定义类的转换

    由其他类型(如int和double)等向自定义类的转换是由构造函数来实现的,只有当类的定义和实现中提供了合适的构造函数时,转换才能通过。什么样的构造函数才是合适的构造函数呢?主要有以下几种情况,为便于说明,假设由A类型向自定义的B转换,操作如下所示。

    ❑类定义和实现中给出了仅包括只有一个A类型参数的构造函数。

    ❑类定义和实现中给出了包含一个A类型参数,且其他参数都是有默认值的构造函数。

    ❑类定义和实现中虽然不包含A类型参数,但包含一个C类型参数,此外没有其他参数或者其他参数都有默认值,且A类型参数可隐式转换为C类型参数。

    用文字解释似乎很枯燥,来看示例代码9.12。

    代码9.12 由其他类型转换为自定义类型Conversion1


    <————————————文件名:example912.cpp———————————————> 01 #include<iostream> 02 using namespace std; 03 class anotherpoint//anotherpoint类定义 04 { 05 private://private成员列表 06 double x; 07 double y; 08 public: 09 anotherpoint(double xx=1,double yy=1)//构造函数,带默认参数值 10 { 11 x=xx; 12 y=yy; 13 } 14 double getX()//成员函数,访问private成员x 15 { 16 return x; 17 } 18 double getY()//成员函数,访问private成员y 19 { 20 return y; 21 } 22 }; 23 class point//point类定义 24 { 25 private://private成员列表 26 int xPos; 27 int yPos; 28 public: 29 point(int x=0,int y=0)//构造函数,带默认参数,两个int型变量 30 { 31 xPos=x; 32 yPos=y; 33 } 34 point(anotherpoint aP)//构造函数,参数为anotherpoint类对象 35 { 36 xPos=aP. getX(); 37 yPos=aP. getY(); 38 } 39 void print()//输出函数,点的信息 40 { 41 cout<<"("<<xPos<<","<<yPos<<")"<<endl; 42 } 43 }; 44 45 int main() 46 { 47 48 point p1;//创建point类对象p1,采用带默认参数的构造函数,即x=0、y=0 49 p1=5;//等价于p1=point(5,0); 50 p1. print();//输出点p1的信息 51 double dX=1. 2;//声明一个double变量dX 52 p1=dX;//等价于p1=point(int(dX),0) 53 p1. print();//输出点p1的信息 54 55 anotherpoint p2;//创建anotherpoint类的对象p2,带默认参数的构造函数,xx=yy=1 56 p1=p2;//等价于p1=point(p2); 57 p1. print();//输出点p1的信息 58 return 0; 59 }

    输出结果如下所示。


    (5,0) (1,0) (1,1)

    【代码解析】代码中分别进行了int型、double型和anotherpoint型向point类的转换,由于point类中提供了构造函数“point(int x=0,int y=0)”,这样,编译器将“p1=5”解释为“p1=point(5,0)”,先创建一个point类临时对象,再调用赋值运算符对p1进行赋值。对于语句“p1=dX;”,程序首先将double型变量dx转换为int型,再调用构造函数生成临时对象,最后用赋值运算符对p1进行赋值。

    代码第56行,语句“p1=p2;”被编译器解释为“p1=point(p2);”,这时,构造函数“point(anotherpoint ap);”被调用,同样先生成一个point类临时对象,再调用赋值运算符完成对p1的赋值。

    注意

    能接受一个参数的构造函数才能称为转换函数,多出来的参数必须有默认值。

    不仅仅在赋值运算时,在对象初始化、函数参数传递和函数返回时,都会发生隐式转换。除了隐式调用外,程序中还可以用诸如以下的形式来实现显式的类型转换。


    p1=point(5); p1=point(dX); p1=point(p2);隐式转换往往会出现一些意想不到的问题,使用关键字explicit可有效地阻止隐式类型的转换,也就是说,如果代码9.12中的构造函数,如下所示。 point(anotherpoint ap)改为如下形式。 explicit point(anotherpoint ap)

    那么,包括“p1=p2;”在内的由anotherpoint类对象向point类对象的隐式转换都会被编译器认定为非法,必须使用显式转换“p1=point(p2);”的形式才能完成转换。

    注意

    “p1=(point)p2;”的形式也是合法的,这是C语言的用法,推荐采用C++模式。