C的隐式类型转换
隐式类型转换分三种,即算术转换、赋值转换和输出转换。
1.算术转换
进行算术运算(加、减、乘、除、取余以及符号运算)时,不同类型数招必须转换成同 一类型的数据才能运算,算术转换原则为:
在进行运算时,以表达式中最长类型为主,将其他类型位据均转换成该类型,如:
(1)若运算数中有double型或float型,则其他类型数据均转换成double类型进行运 算。
(2)若运算数中最长的类型为long型.则其他类型数均转换成long型数。
(3)若运算数中最长类型为int型,则char型也转换成int型进行运算。算术转换是在 运算过程中自动完成的。
2.赋值转换
进行赋值操作时,赋值运算符右边的数据类型必须转换成赋值号左边的类型,若右边的数据类型的长度大于左边,则要进行截断或舍入操作。
下面用一实例说明:
char ch;
int i,result;
float f;
double d;
result=ch/i+(f*d-i);
(1)首先计算 ch/i,ch → int型,ch/i → int型。
(2)接着计算 f*d-i,由于最长型为double型,故f→double型,i→double型,f*d-i→double型。
(3)(ch/i) 和(f*d-i)进行加运算,由于f*d-i为double型,故ch/i→double型,ch/i+(f*d-i)→double型。
(4)由于result为int型,故ch/i+(f*d-i)→double→int,即进行截断与舍入,最后取值为整型。
3.输出转换
在程序中将数据用printf函数以指定格式输出时,当要输出的盐据类型与输出格式不符时,便自动进行类型转换,如一个long型数据用整型格式(%d)输出时,则相当于将long型转换成整型(int)数据输出;一个字符(char)型数据用整型格式输出时,相当于将char型转换成int型输出。
注意:较长型数据转换成短型数据输出时,其值不能超出短型数据允许的值范围,否则 转换时将出错。如:
long a=80000;
printf("%d",a);
运行结果为14464,因为int型允许的最大值为32767,80000超出此值,故结果取以32768为模的余数,即进行如下取余运算:
(80000-32768)-32768=14464;
输出的数据类型与输出格式不符时常常发生错误,
如:int d=9;
printf("%f",d);
或
float c=3.2;
printf("%d",c);
将产生错误的结果。
C++的隐式类型转换
#include <string>
#include <iostream>
using namespace std;
class Fruit //定义一个类,名字叫Fruit
{
string name; //定义一个name成员
string colour; //定义一个colour成员
public:
bool isSame(const Fruit &otherFruit) //期待的形参是另一个Fruit类对象,测试是否同名
{
return name == otherFruit.name;
}
void print() //定义一个输出名字的成员print()
{
cout<<colour<<" "<<name<<endl;
}
Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst){} //构造函数
Fruit(){}
};
int main()
{
Fruit apple("apple");
Fruit orange("orange");
cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl; //没有问题,肯定不同
cout<<"apple = \"apple\" ?:"<<apple.isSame(string("apple")); //用一个string做形参?
return 0;
}
你会发现最后的使用上,我们用一个string类型作一个期待Fruit类形参的函数的参数,结果竟然得出了是true(1),不要感到奇怪,这就是我现在要讲的东西,隐式类类型转换:“可以用单个实参来调用的构造函数定义了从形参类型到该类型的一个隐式转换。”(C++ Primer)首先要单个实参,你可以把构造函数colour的默认实参去掉,也就是定义一个对象必须要两个参数的时候,文件编译不能通过。然后满足这个条件后,系统就知道怎么转换了,不过这里比较严格:)以前我们构造对象的时候Fruit apple("apple")其实也已经有了一个转换,从const char *的C字符串格式,转为string,在这里,你再apple.isSame("apple")的话,蠢系统不懂得帮你转换两次,所以你必须要用 string()来先强制转换,然后系统才知道帮你从string隐式转换为Fruit,当然其实你自己也可以帮他完成。 cout<<"apple = \"apple\" ?:"<<apple.isSame(Fruit("apple"));这样。参考例子1.2 :Fruit apple = Fruit("apple"); //定义一个Fruit类对象apple。也就是这样转换的。不过这就叫显式转换了,我们不标出来,系统帮我们完成的,叫隐式的贝。这里要说的是,假如你显示转换就可以不管有多少参数了,比如在前面提到的必须需要两个参数的构造函数时的例子。
例2:
#include <string>
#include <iostream>
using namespace std;
class Fruit //定义一个类,名字叫Fruit
{
string name; //定义一个name成员
string colour; //定义一个colour成员
public:
bool isSame(const Fruit &otherFruit) //期待的形参是另一个Fruit类对象,测试是否同名
{
return name == otherFruit.name;
}
void print() //定义一个输出名字的成员print()
{
cout<<colour<<" "<<name<<endl;
}
Fruit(const string &nst,const string &cst):name(nst),colour(cst){} //构造函数
Fruit(){}
};
int main()
{
Fruit apple("apple","green");
Fruit orange("orange","yellow");
cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl; //没有问题,肯定不同
cout<<"apple = \"apple\" ?:"<<apple.isSame(Fruit("apple","green")); //显式转换
return 0;
}
在你不想隐式转换,以防用户误操作怎么办?C++提供了一种抑制构造函数隐式转换的办法,就是在构造函数前面加explicit关键字,你试试就知道,那时你再希望隐式转换就会导致编译失败,但是,要说明的是,显式转换还是可以进行。