当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 用转换操作符保护代码的安全

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 72 ::
收藏到网摘: n/a

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

作者: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 类型的参数: