C++ 使用类(十)下

1.类的自动转换和强制类型转换

下面的语句都将导致数值类型转换:

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++语言不自动地转换不兼容的类型

下面的语句就是非法的,因为左边是指针类型,而右边是数字

int *p = 10;//type clash 

虽然计算机内部可能使用整数来表示地址,但从概念中说,整数和指针完全不同。例如,不能计算指针的平方。然而在无法自动转换时,可以使用强制类型转换:

int *p = (int*) 10;//ok,p and (int*) 10 both pointers

上述语句将10强制转换为int指针类型(即int *类型),将指针设置为地址10

可以设计一种合适的类型,以两种方式(磅和英石)来表示重量。对于在一个实体中包含一个概念的两种表示来说,类提供了一种非常好的方式。

示例:
stonewt.h:

#ifndef STONE_H_
#define STONE_H_
class Stonewt
{
private:
	enum { Lbs_per_stn = 14 };
	int stone;
	double pds_left;
	double pounds;
public:
	Stonewt(double lbs);
	Stonewt(int stn, double lbs);
	Stonewt();
	~Stonewt();
	void show_lbs() const;
	void show_stn() const;
};

#endif // !STONE_H_

Stonewt类有三个构造函数,让您能够将Stonewt对象初始化为一个浮点数(单位为磅)或两个浮点数(分别代表英石和磅)。也可以创建Stonewt对象,而不进行初始化:

Stonewt blossem(132.5);//weight = 132.5 pounds
Stonewt buttercup(10, 2);//weight = 10 stone,2 pounds
Stonewt bubbles;//weight = default value

stonewt.cpp:

#include <iostream>
using std::cout;
#include"stonewt.h"
Stonewt::Stonewt(double lbs)
{
	stone = int(lbs) / Lbs_per_stn;
	pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
	pounds = lbs;
}

Stonewt::Stonewt(int stn, double lbs)
{
	stone = stn;
	pds_left = lbs;
	pounds = stn * Lbs_per_stn + lbs;
}

Stonewt::Stonewt()
{
	stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()
{
}

void Stonewt::show_stn() const
{
	cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs() const
{
	cout << pounds << " pounds\n";
}

因为Stonewt对象表示一个重量,所有可以提供一些将整数或浮点数转换为Stonewt对象的方法。在C++中,接受一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。下面的构造函数用于将double类型的值转换为Stonewt类型:

Stonewt(double lbs);//template for double-to-Stonewt conversion

可以编写这样的代码:

Stonewt myCat;//create a Stonewt object
myCat = 19.6;//use Stonewt(double) to convert 19.6 to Stonewt

程序将使用构造函数Stonewt(double)来创建一个临时的Stonewt对象,并将19.6作为初始化值。随后,采用逐成员赋值方式将该临时对象的内容复制到myCat中。这一过程中成为隐式转换,因为它是自动进行的,而不需要显示强制类型转换。
只有接受一个参数的构造函数才能作为转换函数。下面的构造函数有两个参数,因此不能来转换类型:

Stonewt(int stn,double lbs);// not a conversion function

然而,如果给第二个参数提供默认值,它便可用于转换int:

Stonewt(int stn,double lbs = 0);//int-to-Stonewt conversion

将构造函数用作自动类型转换函数似乎是一项不错的特性。但其实这是会导致意外的类型转换的。因此C++新增了关键字explicit,用于关闭这种自动特性。也就是说,可以这样声明构造函数:

explicit Stonewt(double lbs);

这将关闭隐式转换,但仍然允许显式转换,即显式强制类型转换

Stonewt myCat;
myCat = 19.6;//not valid
mycat = Stonewt(19.6);//ok
mycat =(Stonewt)19.6;//ok

**tip:**只接受一个参数的构造函数定义了从参数类型到类类型的转换。如果使用关键字explicit限定了这种构造函数,则它只能用于显式转换,否则也可以用于隐式转换

编译器在什么时候将使用Stonewt(double)函数呢?如果在声明中使用了关键字explicit,则Stonewt(double)将只用于显式强制类型转换,否则还可以用于下面的隐式转换

⚪将Stonewt对象初始化为double时
⚪将double值赋给Stonewt对象时
⚪将double值传递给接受Stonewt参数的函数时
⚪返回值被声明为Stonewt的函数试图返回double值时
⚪在上述任意一种情况下,使用可转换为double类型的内置类型时

函数原型化提供的参数匹配过程,允许使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,因此调用存在二义性

完善上述的示例:
stone.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 taft(21, 8);
	cout << "The celebrity weighed ";
	incognito.show_stn();
	cout << "The detective weighed";
	wolfe.show_stn();
	cout << "The President weighed ";
	taft.show_lbs();
	incognito = 276.8;
	taft = 325;
	cout << "After dinner, the celebrity weighed ";
	taft.show_lbs();
	display(taft, 2);
	cout << "The wrestler weighed even more.\n";
	display(422, 2);
	cout << "No stone left unearned\n";
	return 0;
}

void display(const Stonewt & st, int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << "Wow! ";
		st.show_stn();
	}
}

在这里插入图片描述
当构造函数只接受一个参数时,可以使用下面的格式来初始化类对象:

Stonewt incognito = 275;

这等价于前面介绍过的另外两种格式:

Stonewt incognito(275);
Stonewt incognito = Stonewt(275);

最后还需要看下面的函数调用:

display(422,2);

display()的原型表明,第一个参数应是Stonewt对象(Stonewt和Stonewt &形参都与Stonewt实参匹配)。遇到int参数时,编译器查找构造函数Stonewt(int),以便将该int转换为Stonewt类型。由于没有找到这样的构造函数,因此编译器寻找接受其他内置类型(前提是int可以转换为这种类型)的构造函数。Stone(double)构造函数满足这种要求,因此编译器将int转换为double,然后使用Stonewt(double)将其转换为一个Stonewt对象

2.转换函数
可以像下面这样做吗?

Stonewt wolfe(285.7);
double host = wolfe;

可以这样做,但不是使用构造函数。构造函数只用于从某种类型到类类型的转换。要进行相反的转换,必须使用特殊的C++运算符函数-转换函数。

转换函数使用户定义的强制类型转换:

Stonewt wolfe(285.7);
double host = double(wolfe);
double thinker = (double) wolfe;

也可以让编译器做决定:

Stonewt wells(20,3);
double star = wells;

编译器发现,右侧是stonewt类型,而左侧是double类型,因此它将查看程序员是否定义了与此匹配的转换函数。(如果没有找到这样的定义,编译器将生成错误消息,指出无法将Stonewt赋给double。)

要转换为typeName类型,需要使用这种形式的转换函数:

operator typeName();

请注意以下几点:

⚪转换函数必须是类方法
⚪转换函数不能指定返回类型
⚪转换函数不能有参数

例如,转换为double类型:

operator int();

下面看stonewt的代码
头文件stonewt.h修改:
添加以下两条语句

	operator int() const;
	operator double() const;

stonewt.cpp修改:
添加两个定义:

Stonewt::operator int()const
{
	return int(pounds + 0.5);
}

Stonewt::operator double() const
{
	return pounds;
}

stone.cpp:

#include<iostream>
using std::cout;
#include"stonewt.h"

int main()
{
	Stonewt poppins(9, 2.8);
	double p_wt = poppins;
	cout << "Convert to double =>";
	cout << "Poppins: " << p_wt << "pounds.\n";
	cout << "Convert to int => ";
	cout << "Poppins: " << int(poppins) << " pounds.\n";
	system("pause");
	return 0;
}`在这里插入代码片`

在这里插入图片描述
但程序像double p_wt = poppins;这样隐式转换是好的吗?其实最好是显式的例如:
我写long gone = poppins;则会存在二义性错误
最好可以这样的写法:

long gone = (double) poppins;
long gone = int (poppins);

所以C++11消除了C++98不能用于转换函数的关键字explicit

class Stonewt
{
...
explicit operator int() const;
explicit operator double() const;
};

可以将Stonewt::operator int(){return int(pounds+0.5);}
替换为int Stonewt::Stone_to_Int(){return int (pounds + 0.5);}

所以下面的语句是非法的:

int a = poppins;

但如果替换后可以这样做:

int a = poppins.Stone_to_Int();

——————————————————————————————上一篇:C++ 使用类(十)上

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
DirectX修复工具(DirectX Repair)是一款系统级工具软件,简便易用。本程序为绿色版,无需安装,可直接运行。 本程序的主要功能是检测当前系统的DirectX状态,如果发现异常则进行修复。程序主要针对0xc000007b问题设计,可以完美修复该问题。本程序中包含了最新版的DirectX redist(Jun2010),并且全部DX文件都有Microsoft的数字签名,安全放心。 本程序为了应对一般电脑用户的使用,采用了易用的一键式设计,只要点击主界面上的“检测并修复”按钮,程序就会自动完成校验、检测、下载、修复以及注册的全部功能,无需用户的介入,大大降低了使用难度。在常规修复过程中,程序还会自动检测DirectX加速状态,在异常时给予用户相应提示。 本程序适用于多个操作系统,如Windows XP(需先安装.NET 2.0,详情请参阅“致Windows XP用户.txt”文件)、Windows Vista、Windows 7、Windows 8、Windows 8.1、Windows 8.1 Update、Windows 10,同时兼容32位操作系统和64位操作系统。本程序会根据系统的不同,自动调整任务模式,无需用户进行设置。 本程序的V4.0版分为标准版、增强版以及在线修复版。所有版本都支持修复DirectX的功能,而增强版则额外支持修复c++的功能。在线修复版功能与标准版相同,但其所需的数据包需要在修复时自动下载。各个版本之间,主程序完全相同,只是其配套使用的数据包不同。因此,标准版和在线修复版可以通过补全扩展包的形式成为增强版。本程序自V3.5版起,自带扩展功能。只要在主界面的“工具”菜单下打开“选项”对话框,找到“扩展”标签,点击其中的“开始扩展”按钮即可。扩展过程需要Internet连接,扩展成功后新的数据包可自动生效。扩展用时根据网络速度不同而不同,最快仅需数秒,最慢需要数分钟,烦请耐心等待。如扩展失败,可点击“扩展”界面左上角小锁图标切换为加密连接,即可很大程度上避免因防火墙或其他原因导致的连接失败。 本程序自V2.0版起采用全新的底层程序架构,使用了异步多线程编程技术,使得检测、下载、修复单独进行,互不干扰,快速如飞。新程序更改了自我校验方式,因此使用新版本的程序时不会再出现自我校验失败的错误;但并非取消自我校验,因此程序安全性与之前版本相同,并未降低。 程序有更新系统c++功能。由于绝大多数软件运行时需要c++的支持,并且c++的异常也会导致0xc000007b错误,因此程序在检测修复的同时,也会根据需要更新系统中的c++组件。自V3.2版本开始使用了全新的c++扩展包,可以大幅提高工业软件修复成功的概率。修复c++的功能仅限于增强版,标准版及在线修复版在系统c++异常时(非丢失时)会提示用户使用增强版进行修复。除常规修复外,新版程序还支持C++强力修复功能。当常规修复无效时,可以到本程序的选项界面内开启强力修复功能,可大幅提高修复成功率。请注意,请仅在常规修复无效时再使用此功能。 程序有两种窗口样式。正常模式即默认样式,适合绝大多数用户使用。另有一种简约模式,此时窗口将只显示最基本的内容,修复会自动进行,修复完成10秒钟后会自动退出。该窗口样式可以使修复工作变得更加简单快速,同时方便其他软件、游戏将本程序内嵌,即可进行无需人工参与的快速修复。开启简约模式的方法是:打开程序所在目录下的“Settings.ini”文件(如果没有可以自己创建),将其中的“FormStyle”一项的值改为“Simple”并保存即可。 新版程序支持命令行运行模式。在命令行中调用本程序,可以在路径后直接添加命令进行相应的设置。常见的命令有7,分别是设置语言的命令、设置窗口模式的命令,设置安全级别的命令、开启强力修复的命令、设置c++修复模式的命令、控制Direct加速的命令、显示版权信息的命令。具体命令名称可以通过“/help”或“/?”进行查询。 程序有高级筛选功能,开启该功能后用户可以自主选择要修复的文件,避免了其他不必要的修复工作。同时,也支持通过文件进行辅助筛选,只要在程序目录下建立“Filter.dat”文件,其中的每一行写一个需要修复文件的序号即可。该功能仅针对高级用户使用,并且必须在正常窗口模式下才有效(简约模式时无效)。 本程序有自动记录日志功能,可以记录每一次检测修复结果,方便在出现问题时,及时分析和查找原因,以便找到解决办法。 程序的“选项”对话框中包含了7项高级功能。点击"常规”选项卡可以调整程序的基本运行情况,包括日志记录、安全级别控制、调试模式开启等。只有开启调试模式后才能在C
©️2020 CSDN 皮肤主题: 护眼 设计师:闪电赇 返回首页

打赏

精神小伙的青春

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值