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

2016-01-29 12:25 11 1 收藏

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

【 tulaoshi.com - C语言心得技巧 】

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

作者:Danny Kalev
编译:MTT 工作室

原文出处:Preserve Code Safety with Conversion Operators

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com)
摘要:不经意的对象转换常常严重地危害代码的安全。幸运的是,转换操作符允许你根据实际情况来启用和禁用转换,这有助于避免出现病态行为。

  某些对象必须要被转换成低级形式,反之亦然。例如,使用 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 首先被求值。正如你所看到的,这一部分没什么问题,产生的结果也是正确的。问题出在赋值上。编译器进行赋值的表达式如下:

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com)
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 类型的参数:

来源:http://www.tulaoshi.com/n/20160129/1486028.html

延伸阅读
C++ 中重载 + 操作符的正确方法 作者:Danny Kalev 编译:MTT 工作室 原文出处:Overloading Operator + the Right Way 摘要: 本文概要性地介绍如何选择正确的策略来为用户定义类型重载 + 操作符。 用户...
与C一样,C++使用布尔表达式简化求值法(short-circuit evaluation)。这表示一旦确定了布尔表达式的真假值,即使还有部分表达式没有被测试,布尔表达式也停止运算。例如: char *p; ... if ((p != 0) && (strlen(p) 10)) ... 这里不用担心当p为空时strlen无法正确运行,因为假如p不等于0的测试失败,st...
标量(scalar)数据类型 标量(scalar)数据类型没有内部组件,他们大致可分为以下四类: . number . character . date/time . boolean 表1显示了数字数据类型;表2显示了字符数据类型;表3显示了日期和布尔数据类型。 表1 Scalar Types:Numeric Datatype Range Subtypes description BINARY_INTEGER...
1、using 按照msdn的解释: using 语句定义一个范围,在此范围的末尾将处理对象。 举例: class TestUsing:IDisposable { public void Dispose() { Console.WriteLine("Dispose"); } public void Method() { Console.WriteLine("Do a method"); } } 调用这个类: using(TestUsing tu...
标签: PHP
四、 扩展"instanceof"操作符的使用:嵌套(X)HTML widget 好。你已经看到了"instanceof"操作符在被直接注入到页面生成器类的输入 对象 进行类型检查方面所表现出的良好功能。现在,我将再进一步来把一个检查例程添加到(X)HTML widget类的构造器和"getHTML()"方法中,这样它们可以接受其它的widget作为输入参数。请检查下面...

经验教程

608

收藏

94
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部