59.类的自动转换和强制类型转换
程序清单11.16 stonewt.h
#pragma once
//stone.h -- Stonewt类声明
#ifndef STONEWT_H_
#define STONEWT_H_
class Stonewt
{
private:
enum {Lbs_per_stn = 14};//pounds per stone
int stone;//whole stone
double pds_left;//fractional pounds
double pounds;//enrire weight in pounds
public:
Stonewt(double lbs);//constructor for double pounds
Stonewt(int stn, double lbs);//constructor for stone, lbs
Stonewt();//default constructor
~Stonewt();
void show_lbs() const;//show weight in pounds format
void show_stn() const;//show weight in stone format
};
#endif
说明:这个类并非真的需要声明析构函数,因为自动生成的默认构造函数就很好。另外,提供显示的声明可以为以后做好准备,以防必须定义构造函数。
程序清单11.17 stonewt.cpp
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1
//stone.cpp -- Stonewt methods
#include <iostream>
using std::cout;
#include "stonewt.h"
//construct Stonewt object from double value
Stonewt::Stonewt(double lbs)//constructor for double pounds
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
Stonewt::Stonewt(int stn, double lbs)//constructor for stone, lbs
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt::Stonewt()//default constructor, wt = 0
{
stone = pounds = pds_left = 0;
}
Stonewt::~Stonewt()
{
}
void Stonewt::show_lbs() const//show weight in pounds format
{
cout << pounds << " pounds\n";
}
void Stonewt::show_stn() const//show weight in stone format
{
cout << stone << " stone, " << pds_left << " pounds\n";
}
因为Stonewt对象表示一个重量,所以可以提供一些整数或浮点值转换为Stonewt对象的方法。在C++中,接受一个参数的构造函数支持将类型与该参数相同的值转换为类。下面的构造函数用于将double类型的值转换为Stonewt类型:
Stone(double lbs);
也就是说,可以编写这样的代码:
Stonewt myCat;//创建一个Stonewt对象
myCat = 19.6;//使用Stonewt(double)将19.6转换为Stonewt
程序员将使用构造函数Stonewt(double)来创建一个临时Stonewt对象,并将19.6作为初始化值。随后,采用逐成员赋值方式将该临时对象的内容复制到myCat中。这一过程称为隐式转换,因为它是自动进行的,而不需要显式强制类型转换。
只接受一个参数的构造函数才能作为转换函数。下面的构造函数有两个参数,因此不能用来转换类型:
Stonewt(int stn, double lbs);
然而,如果给第二个参数提供默认值,它便可以用于转换int:
Stonewt(int stn, double lbs = 0);
有时会导致意外的类型转换。因此,C++新增了关键字explicit,用于关闭这种自动类型。也就是说,可以这样声明构造函数:
explicit Stonewt(double lbs);
这将关闭上述示例的隐式转换,但仍然可以显示强制类型转换:
Stonewt myCat;
myCat = 19.6;
mycat = Stonewt(19.6);
mycat = (Stonewt) 19.6;
注意:只接受一个参数的构造函数定义了从参数类型到类类型的转换。如果使用关键字explicit限定了这种构造函数,则它只能用于显式转换,否则也可以用于隐式转换。
编译器将使用Stonewt(double)函数的时机
如果在声明中使用了关键字explicit,则Stonewt(double)将只用于显式强制类型转换,否则还可以用于下面的隐式转换。
●将stonewt对象初始化为double值时
●将double值赋值给Stonewt对象时
●将double传递给接受Stonewt参数的函数时
●返回值被声明为Stonewt的函数试图返回double值时
●在上述任意一种情况下,使用可转换为double类型的内置类型时
当且仅当转换不存在二义性时,才会进行这种二步转换。
程序清单11.18 stone.cpp
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1
//stone.cpp -- 用户定义版本
//和stonewt.cpp联合编译
#include <iostream>
using std::cout;
#include "stonewt.h"
void display(const Stonewt& st, int n);
int main()
{
Stonewt incognito = 275;//使用构造函数初始化
Stonewt wolfe(285.7);//等价于Stonewt wolfe = 285.7;
Stonewt taft(21, 8);
cout << "The celebrity weighed ";
incognito.show_stn();
cout << "The decetive weighed ";
wolfe.show_stn();
cout << "The President weighed ";
taft.show_lbs();
incognito = 276.8;//使用构造函数转换
taft = 325;//等价于taft = Stonewt(325);
cout << "After dinner, the celebrity weighed ";
incognito.show_stn();
cout << "After dinner, the President weighed ";
taft.show_lbs();
display(taft, 2);
cout << "The wrestler weighed even more.\n";
display(422, 2);
cout << "No stone left unearned\n";
system("pause");
return EXIT_SUCCESS;
}
void display(const Stonewt& st, int n)
{
for (int i = 0; i < n; i++)
{
cout << "Wow! ";
st.show_stn();
}
}
输出:
The celebrity weighed 19 stone, 9 pounds
The decetive weighed 20 stone, 5.7 pounds
The President weighed 302 pounds
After dinner, the celebrity weighed 19 stone, 10.8 pounds
After dinner, the President weighed 325 pounds
Wow! 23 stone, 3 pounds
Wow! 23 stone, 3 pounds
The wrestler weighed even more.
Wow! 30 stone, 2 pounds
Wow! 30 stone, 2 pounds
No stone left unearned
请按任意键继续. . .
程序说明:
当构造函数只接受一个参数时,可以使用下面的格式来初始化类对象:
Stonewt incognito = 275;
这等价于前面介绍过的另外两种格式:
Stonewt incognito(275);
Stonewt incognito = Stonewt(275);
接下来,请注意程序清单11.18的下面两条语句:
incognito = 276.8;
taft = 325;
第一条赋值语句使用接受double参数的构造函数,将276.8转换为一个Stonewt值,这将incognito的pound成员设置为276.8。因为该语句使用了构造函数,所以还将设置stone和pds_left成员。同样,第二条赋值语句将一个int值转换为double类型,然后使用Stonewt(double)来设置全部3个成员。
注意:
display(422, 2);
display()原型表示,第一个参数是Stone对象(Stonewt 和Stonewt &形参都与Stonewt实参匹配)。遇到int参数时,编译器查找构造函数Stonewt(int),以便将该int值转换为Stonewt类型。没找到,于是匹配率Stonewt(double)。