现在的位置: 首页 > 综合 > 正文

要小心隐式类型转换

2013年09月07日 ⁄ 综合 ⁄ 共 1631字 ⁄ 字号 评论关闭

 C++中包含很多隐含规则,如果对这些隐含规则掌握不清楚,往往出了问题都无从查起,隐式类型转换就是其中之一。
 (1)、单参数构造函数(single argument constructor)会导致隐式类型转换
 例如,你有这样一个类:
 class MyClass
 {
  char *szBuffer;
 public:
  MyClass()
  {
   szBuffer=NULL;
  }
  MyClass(int size)
  {
   szBuffer=new char[size];
   memset(szBuffer,0,size);
  }
  ~MyClass()
  {
   delete[] szBuffer;
  }
  ....
 };
 写一个构造函数带一个int参数来指定初始分配多大的缓冲似乎无可厚非,但是如果您或者别人不小心写下了这么一句:
 //MyClass test;
 test=256;
 那么编译器会先使用“MyClass(int size)”构造一个临时对象,然后再调用赋值操作符,将这个临时对象赋值给test对象。即使你很谨慎的为MyClas写了赋值操作符(const MyClass& operator = (const MyClass& other)),情况也是一样糟糕,因为test对象的内容被清空了。
 如果你没有写赋值操作符,那么情况将一片混乱!编译器会使用默认的赋值操作,即位拷贝,而临时对象在完成赋值操作之后会被释放,临时对象的析构函数被调用,此时临时对象的szBuffer和test的szBuffer成员已经指向了同一块内存,所以后续对test的szBuffer成员的操作将无法预料。
 为了避免这个问题,C++引入了explicit关键字,将函数声名做一下修改:explicit MyClass(int size),“ test=256;”这一句就无法编译通过了。

 (2)、赋值操作符也可以引起类型转换
 接上例,如果MyClass有一个成员函数“const MyClass& operator = (int t)”,那么“test=256;”就又可以编译通过了,不过这种写法在实际中很少见到。
 
 (3)、慎用类的类型转换函数(user-defined conversion function)
 用MFC的时候觉得CString,CRect很方便,如果函数的参数是LPCTSTR(即const char*)或者LPRECT(即RECT*),对象依然可以传进去。这就是因为CString和CRect类都有相应的作符。类型转换函数有时是很方便的,例如有一个类:
 class MyColor
 {
 public:
  unsigned char A,R,G,B;

  operator unsigned int () const
  { 
   return (A << 24) | (R << 16) | (G << 8) | B; 
  }
 };
 MyColor用来分别存储一个颜色值的a,r,g,b四个分量,把这个类的实例转换成一个32位的值是一个常用的操作,所以写了这样一个成员函数,用起来很方便:
 MyColor test;
 unsigned int a=test;
 
 如果写下了这样一句,目的是比较每个分量的大小,那就要小心了:
 MyColor test;
 MyColor test2;
 bool b=test>test2;
 虽然MyColor并没有写“operator >”,但是这一句还是可以编译运行的。编译器经过函数重载解析,会对test和test2进行隐式类型转换,然后在所有的>操作符中找到匹配的。“test>test2”实际上是将test和test2都转换成了unsigned int,然后再进行比较!

参考资料:
《C++ Primer》 Stanley B.Lippman、Josee Lajoie,潘爱民、张丽译
《Effective C++》 Scott Meyers,侯捷译
《C++标准程序库》 Nicolai M.Josuttis,候捷、孟岩译
 

【上篇】
【下篇】

抱歉!评论已关闭.