如果我们把WebBrowse相关的功能设计为non-member函数,那么可以将其功能相关的函数的声明单独放在一个头文件中,然后在一个命名空间下。这时候如果我们相扩展相关的这些功能,只需要像其他功能函数一样把声明入在头文件里即可。
而这种切割方式并不适用于class成员函数,因为一个class必须整体定义,不能被切割为片断。
请记住
宁可拿non-member non-friend函数替换member函数。这样做可以增加封装性、包裹弹性和机能扩充性。
条款24:若所有参数皆需要类型转换,请为些采用non-member函数
当我们为一个有理数类的设计一个乘法操作符的重载函数,如果我们把它作为类的成员:
class Rational { public: //... const Rational operator*(const Rational &lhs); };
当我们尝试混合算术的时候,你会发现只有一半行得通:
Rational result, oneHalf; result = oneHalf * 2; result = 2 * oneHalf;
上面第二个赋值语句是错误的,因为它等价于result=2.operator*(oneHalf),这显然是错误的。
而第2条语句等价于result=oneHalf.operator(2),它可以执行成功是因为2发生了隐式类型转换,因为Rational有一个non-explicit的接受int形参的构造函数。
所以,如果我们想执行上面的操作,我们需要将这个重载函数设计为non-member函数。
const Rational operator*(const Rational& lhs, const Rational& rhs);
如果你需要为某个函数的所有参数(包括被this指针所指向的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。
条款25:考虑写出一个不抛异常的swap函数
1,当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。
2,如果你提供一个member swap,也该提供一个non-member swap来调用前者,对于classes(而非templates),也请特化std::swap。
3,调用swap时应针对std::swap使用using声明式,然后调用swap并且不带任何“命名空间资格修饰”。
4,为“用户定义类型”进行std template全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西。