分享
 
 
 

用转换操作符保护代码的安全

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

用转换操作符保护代码的安全

作者:Danny Kalev

编译:MTT 工作室

原文出处:Preserve Code Safety with Conversion Operators

摘要:不经意的对象转换常常严重地危害代码的安全。幸运的是,转换操作符允许你根据实际情况来启用和禁用转换,这有助于避免出现病态行为。

某些对象必须要被转换成低级形式,反之亦然。例如,使用 std::string 对象的程序员必须将之转换为 char 指针,请看下面例子:

string inf="mydata.txt";

ifstream infile(inf.c_str());// 必须要转成 const char*

同样,PSOIX 程序员需要将 <fstream> 对象转换成文件描述符以便

使用本地系统调用。

如何在不危及代码安全性的前提下让对象自动转换到其底层类型呢?

使用转换操作符和 explicit 构造函数来创建具备双接口的对象,从而避免病态行为转换。

提出问题:

商业和金融应用常常将币值表示成对象,而不是原始的浮点类型。之所以要这样做有几个原因:

类型安全:人为错误更容易被发现;

可移植性:由于对用户隐藏实现细节,代码具有更好的可移植性;

业务逻辑:类允许你强化了业务逻辑规则。例如:美元(US dollar)类知道一美元是 100 美分(cents),而科威特第纳尔(dinar)类知道一第纳尔是

1000 菲尔斯(fils)。这种差别将影响

I/O 格式

下面是一个简化了的表示美国货币的类:

class USD

{

private:

__int64 dollars; //或者 long long, 依赖编译器

int cents;

public:

USD(__int64 d=0, int c=0) :

dollars(d), cents(c) {}

friend bool operator==(const USD& d1, const USD& d2);

//...other overloaded operators and functions

};

唉,许多数学函数如:pow() 和 sqrt()都只认浮点变量。为了克服这个问题人们总是去重载关系操作符和算子。然而,你会发现这将带来大量无谓的编码,测试和维护工作。你想要的只不过是一个双接口:在适当的上下文中,USD

类对象除了应该提供安全的自动的到基本类型的转换外,它还应该提供上述所列的优点。

使用转换操作符:

转换操作符在适当的上下文中将其对象自动转换成不同的类型。在类 USD 中,最自然的转换是到浮点的转换:USD payment(203, 67);

此时,你想将支付对象转换为浮点值 203.76。

转换操作符没有返回值(从操作符的名字上判断),也不带任何参数:

class USD

{

public:

operator double() //conversion operator

{

double temp=(dollars*100)+cents;

return temp/100;

}

};

让我们看看它是如何工作的。假设你想增加 5% 的支付:double res=payment*1.05; //res=210.70

这样能工作得很好,因为进行乘法之前转换操作符自动将支付转换为值 200.67。但是,在 USD

类的设计上有一个严重的缺点。请看下面的代码:

payment=payment*1.05; // 很糟

现在,支付等于 210.00,这当然不是所期望的结果。让我们来看看为什么。右边子表达式 payment*1.05

首先被求值。正如你所看到的,这一部分没什么问题,产生的结果也是正确的。问题出在赋值上。编译器进行赋值的表达式如下:

payment=USD(__int64(200.67*1.05), 0);

乘法表达式的结果被暗中转换为整型(因此丢失分数部分),然后被用作一个临时 USD 对象的参数。这就是为什么它会产生这样一个令人为难的结果。

声明 ‘explicit’构造函数:

为了解决这个问题,首先将构造函数声明为

explicit

class USD

{

public:

explicit USD(__int64 d=0, int c=0):

dollars(d), cents(c){}

...

这样,只有 USD 对象的赋值才被接受:payment=USD(payment*1.05); // 没问题

payment=payment*1.05; // 编译出错

添加另一个构造函数:

其次是添加另一个构造函数,该构造函数带一个 double 类型的参数:

class USD

{

public:

explicit USD(double val)

{

dollars=val; // 拷贝整型部分

long double temp=(val-dollars)*100; // 吸取美分

// 避免截断 e.g., .6699 是 66 而不是 67

cents=temp+0.5;

}

};

在此,构造函数被声明为‘explicit’,以避免不经意的赋值。为了让支付增加 5%,使用如下形式:payment = USD(payment*1.05);

现在,一切都没有问题。混杂的构造函数不经意的转换被阻止,允许依赖转换操作符到 double 的正当转换。

以安全为重:

程序员常常抱怨在类 std::string 中缺乏 const char * 转换操作符。如果 std::string

具备这样的操作符,你可能会写:

string filename;

ifstream inf(filename);

代替丑陋的:

ifstream inf(filename.c_str());

不管怎样,C++ 标准化委员会决定在 std::string 中不包含此类转换操作符,因为它在某些广泛使用 char *

的库中可能导致令人厌恶的 bug。在这种情况下,标准委员会本着以安全为重的思路。与之对照,<fstream>

对象包含到 void * 类型的转换操作符,你可以象下面这样来使用它:

ifstream inf("myfile");

if (inf) // 使用 void * 转换操作符

// 使用此文件

else

// 失败

当你设计自己的类时,应该考虑启用/禁用哪种类型的自动转换。然后,通过定义适当的转换操作符来启用合法转换,而通过声明 explicit

构造函数来阻止不合需要的转换。

作者简介

Danny Kalev 是一名通过认证的系统分析师和软件工程师,专攻 C++ 和形式语言理论。1997 年到 2000

年期间,他是 C++ 标准委员会成员。最近他以优异成绩完成了他在普通语言学研究方面的硕士论文。

业余时间他喜欢听古典音乐,阅读维多利亚时期的文学作品,研究 Hittite、Basque 和 Irish Gaelic

这样的自然语言。其它兴趣包括考古和地理。Danny 时常到一些 C++ 论坛并定期为不同的 C++

网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有