Effective C++学习笔记之第四章(5)
来源:互联网 发布:爱淘宝0.5红包入口 编辑:程序博客网 时间:2024/05/16 10:04
chapter 4 设计与声明
item24:当所有参数都需要隐式类型转换的时候,使用non-member函数
1)如果一个函数的每一个参数都需要一个类型转换(包括可能的this指针),那么这个函数一定是一个non-member函数。下面一步步来分析,假设有一个实数类,需要进行乘法运算:
//实数类的声明class Rational {public: // ctor is deliberately not explicit;allows implicit int-to-Rational conversions Rational(int numerator = 0,int denominator = 1); int numerator() const; // accessors for numerator and int denominator() const; // denominator — see Item 22private: ...public: //假设实数类里面有一个operator*的函数,先不考虑上一个item讲得关于封装性的考虑 const Rational operator*(const Rational& rhs) const;};//如果这样调用,OKRational oneEighth(1, 8);Rational oneHalf(1, 2);Rational result = oneHalf * oneEighth; // fineresult = result * oneEighth; // fine//但是,如果需要进行混合运算result = oneHalf * 2; // fine 代码1result = 2 * oneHalf; // error! 代码2//上述代码的等价形式result = oneHalf.operator*(2); // fine result = 2.operator*(oneHalf); // error!//代码1的进一步的等价形式const Rational temp(2); // create a temporary Rational object from 2result = oneHalf * temp; // same as oneHalf.operator*(temp);
按理来说,乘法运算是可以交换的,没理由说支持某一种顺序,而另一种顺序就是错误的。当然如果Rational的构造函数是explicit的,那么代码1也是错误的,达到一致性了,呵呵。现在分析代码2,由于2是一个整型,所以没有对应的operator*函数,所以编译器会在non-member函数里面去寻找类似于result = operator*(2, oneHalf);但是这个函数不存在,所以最后会出现编译错误。为什么不能上面两个代码,一个可以,而另一个不可以呢。先说代码1,2作为operator*的参数,传进去的时候进行了一个隐式转换,而第二种方法,2是this指针所指的,不是通过参数传的,所以没办法转化。所以这里需要一个non-member函数。
const Rational operator*(const Rational& lhs,const Rational& rhs){ return Rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());}Rational oneFourth(1, 4);Rational result;result = oneFourth * 2; // fineresult = 2 * oneFourth; // hooray, it works!
2)那这里需不需要把operator*作为friend函数呢?答案是no,因为operator*完全可以由Rational的公共接口实现。当然这也揭示了一个道理:与member function对应的是non-member function而不是friend function。不是说一个函数不是member function就一定是friend function。现实生活中,可能朋友也会带来麻烦呢,是吧~
3)当涉及到template C++而不是面向对象C++时,可能会有新的情况需要考虑(见item 46)。so,keep moving.
item25:考虑写出一个不抛出异常的swap函数
1)如果swap的缺省实现码对你的class或者class template提供可接受的效率,那你不需要额外任何事。
2)如果缺省的swap实现版的效率不足(比如你的class或者template中包含了指向实现的指针(pimpl idiom),那么就可以尝试着做一下几件事来提高swap效率。
3)提供一个public swap成员函数,高效的置换类型的两个对象值,比如说涉及到指针的时候,只置换指针的地址即可。这个函数绝不该抛出异常。因为swap缺省版本是以copy构造函数和copy赋值操作符为基础的,而一般情况下两者都允许抛出异常。而你特化的swap一般来说跟默认的swap具有相同的特性。因为你写的swap基本上都是对内置类型进行操作,而内置类型上的操作绝不会抛出异常。
4)在你的class或者template所在的命名空间提供一个non-member的swap,如同item24里面所讲的一样,然后用它来调用上述的swap成员函数。当然如果你的class的定义和这个non-member的swap如果不是另外放在一个命名空间中(也就是和别的class或者typedef什么的混在一起),其功能也可以实现,但是这样一来,不觉得代码很乱?如果是class(非template),同时为class特化std::swap。(PS:说实话,感觉这句话我没理解,可能是因为我对C++的泛型编程不了解,当然希望有人路过的时候留言讨论,如果有新的感悟,我再加上来)
//4)的代码说明namespace WidgetStuff { ... // templatized WidgetImpl, etc. template<typename T> // as before, including the swap class Widget { ... }; // member function ... template<typename T> // non-member swap function; void swap(Widget<T>& a,Widget<T>& b) // not part of the std namespace{ a.swap(b); }}//5)的代码说明template<typename T>void doSomething(T& obj1, T& obj2){ using std::swap; // make std::swap available in this function ... //正确的调用方式,call the best swap for objects of type T swap(obj1, obj2); //错误的调用方式,这样编译器就会默认的只在std命名空间去查找合适的swap函数 std::swap(obj1, obj2); ...}
5)如果调用swap,记得包含一个using声明,使得std::swap可用,并且不要加任何修饰符,直接调用swap。
6)为"用户定义类型"进行std template全特化是好的,但是不要尝试在std内加入某些对std而言全新的东西。
- Effective C++学习笔记之第四章(5)
- Effective C++学习笔记之第四章(5)
- Effective C++学习笔记之第四章(1)
- Effective C++学习笔记之第四章(2)
- Effective C++学习笔记之第四章(3)
- Effective C++学习笔记之第四章(4)
- 《Effective STL》学习笔记(第四部分)
- 《Effective STL》学习笔记(第四部分)
- effective objective-c 2.0 笔记 第四章 :协议与分类
- 《Effective C++》学习笔记
- 《Effective C++》学习笔记
- 《Effective C++》学习笔记
- 《Effective C++》学习笔记
- Effective java笔记-第四章
- Effective Java 学习笔记——第四章(未完待续)
- 《Effective C++》学习笔记(1)
- 《Effective C++》学习笔记(一)
- 《Effective C++》学习笔记(二)
- SVN整理
- 面试难点总结[java篇]
- word复制粘贴的时候出现中括号
- Lucene Scoring Algorithm -- Lucene 分数 计算 算法
- Redis命令总结
- Effective C++学习笔记之第四章(5)
- 一个整数,大于0,不用循环和本地变量,按照n,2n,4n,8n的顺序递增,当值大于5000时,把值按照指定顺序输出来
- GCC常用参数解释
- __FILE__,__LINE__,FUNCTION__实现代码跟踪调试(linux下c语言编程 )
- 使用U盘安装Debian Linux笔记
- NPOI 批量插入图片进Excel
- 编程实现删除字符串中所有给定的子串
- Android 编程下流量监测的实现原理
- 随机模拟的基本思想和常用采样方法(sampling)