将一个标准类型变量的值赋给另一个标准类型的变量时,如果这两种类型兼容,则C++自动将这个值转换为接收变量的类型。
long count = 8; // int value 8 converted to type long
double time = 11; // int value 11 converted to type double
int side = 3.33; // double value 3.33 converted to type int 3
上述赋值语句都是可行的,因为C++看来,各种数值类型都表示相同的东西—一个数字,同时C++包含用于进行转换的内置规则。然而,这些转换将降低精度;而且,C++语言不自动转换不兼容的类型。
int * p = 10; // type clash --- 这个会执行失败,但是呢,允许使用强制类型转换
然而,当自动类型转换失败时,可以使用强制类型转换。
int * p = (int *) 10; // ok, p and (int *) 10 both pointers
针对下面这三个构造函数:
Stonewt(double lbs); // constructor for double pounds
可以使用以下方式初始化对象:
Stonewt myCat; // create a Stonewt object
myCat = 19.6; // use Stonewt(double) to convert 19.6 to Stonewt
程序将使用构造函数Stonewt(double)来创建一个临时的Stonewt对象, 并将19.6作为初始化值。随后,采用逐成员赋值方式将该临时对象的内容复制到myCat中。这一过程称为隐式转换,因为是自动进行的,而不需要显式强制类型转换。
只有接受一个参数的构造函数才能作为转换函数。
然而,如果给第二个参数提供默认值,他便可用于转换int:
Stonewt(int stn, double lbs = 0); // int-to-Stonewt conversion
什么时候使用构造函数隐式类型转换功能
下面详细介绍最后一点,函数原型化提供的参数匹配过程,允许使用Stonewt(double)构造函数来转换其他数值类型。也就是说,下面两条语句都首先将int转换为double,然后使用Stonewt(double)构造函数。
Stonewt Jumbo(7000); // uses Stonewt(double), converting int to double
Jumbo = 7300; // uses Stonewt(double), converting int to double
然而,当且仅当转换不存在二义性时,才会进行这种二步转换。也就是说,如果这个类还定义了构造函数Stonewt(long)则编译器将拒绝这些语句,可能指出:int可被转换为long或double,因此调用存在二义性。
随着程序员拥有更丰富的C++经验,将会发现自动类型转换并非总是合乎需要的,因为这会导致意外的类型转换。因此,C++新增了关键字explicit,用于关闭自动类型转换,也就是说,可以这样声明构造函数:
explicit Stonewt(double lbs); // no implicit conversions allowed
这将关闭隐式转换,但仍然允许显式转换,即显式强制类型转换。
Stonewt myCat; // create a Stonewt object
myCat = 19.6; // not valid if Stonewt(double) is declared as explicit
mycat = Stonewt(19.6); // ok, an explicit conversion
mycat = (Stonewt) 19.6; // ok, old form for explicit typecast
构造函数只用于从某种类型到类类型的转换。要进行相反的转换,必须使用特殊的C++运算符函数—转换函数。
转换函数是用户定义的强制类型转换,可以像使用强制类型转换那样使用它们。
要转换为typeName类型,需要使用这种形式的转换函数:
operator typeName();
有三个注意事项:
例如,转换为double类型的函数的原型如下:
operator double();
转换为int类型是采用四舍五入的方式。
隐式转换
Poppins有两个转换函数,分别是转换为int和double类型。
double p_wt = poppins;
隐式转换缺点
针对上述含糊的情况,可以使用显式类型转换如下:
long gone = (double) poppins; // use double conversion
long gone = int (poppins); // use int conversion
隐式转换的函数所存在的问题是:在用户不希望进行转换时,转换函数也可能进行转换。
class Stonewt
{
...
// conversion functions
explicit operator int() const;
explicit operator double() const;
};
int Stonewt::Stone_to_Int() { return int (pounds + 0.5); }
原则上说,最好使用显式转换,而避免隐式转换。在C++98中,关键字explicit不能用于转换函数,但C++11消除了这种限制。因此,在C++11中,可将转换运算符声明为显式的。
应谨慎地使用隐式转换函数。通常,最好选择仅在被显式调用时才会执行的函数。
有两种方式:
成员函数
Stonewt Stonewt::operator+(const Stonewt & st) const
{
double pds = pounds + st.pounds;
Stonewt sum(pds);
return sum;
}
And 友元函数
Stonewt operator+(const Stonewt & st1, const Stonewt & st2)
{
double pds = st1.pounds + st2.pounds;
Stonewt sum(pds);
return sum;
}
针对这两个操作符重载,第一个和第二个+重载都允许使用以下语句:
语句组合1:
Stonewt jennySt(9, 12);
Stonewt bennySt(12, 8);
Stonewt total;
total = jennySt + bennySt;
语句组合2:需要隐式调用构造函数转换类型
Stonewt jennySt(9, 12);
double kennyD = 176.0;
Stonewt total;
total = jennySt + kennyD;
但是,只有第二个+重载允许使用以下语句,但是需要隐式调用构造函数转换类型:
Stonewt jennySt(9, 12);
double pennyD = 146.0;
Stonewt total;
total = pennyD + jennySt;
原因是:转换发生在成员函数参数,而不是成员函数调用者。
Stonewt operator+(double x); // member function
friend Stonewt operator+(double x, Stonewt & s);
语句组合1和语句组合2都可以匹配第一个,但是语句组合1需要使用转换函数double(),语句组合2匹配第二个。
第一种方式的程序更短,因为定义的函数更少。但是需要调用构造函数形成临时的对象,增加了程序运行时间和内存开销。第二种方式程序更长,程序员所做的工作更多,但是运行速度较快。