Effective C++第四篇,扩展的有点多...
(四).设计与声明
____________________________________________________________________________________________________________________________________
条款24:若所有参数皆需类型转换,请为此采用non-member函数
#1.如果你需要为某个函数的所有参数(包括被 this指针所指的那个隐喻参数)进行
类型转换,那么这个函数必须是个 non-member。
//假设有个有理数类:
class Rational{
public:
Rational(int numrator=0, int denomination=1);
int numerator()const;
int denomination()const;
...
};
//如果operator*写成Rational成员函数的话:
class Rational{
public:
...
const Rational operator*(const Rational& rhs)const;
...
};
Rational oneEigth(1,8); //很好
Rational oneHalf(1,2); //很好
Rational result = oneHalf * oneEighth; //很好
result = result * oneEighth //很好
//当尝试混合运算时:
result = oneHalf*2; //result = oneHalf.operator*(2);很好
result = 2*oneHalf; //result = 2.operator*(oneHalf);出错,继续尝试non-member函数
//当编译器试图调用non-member函数 result = operator*(2, oneHalf);时
//依旧没有找到对应的non-member函数,因此最终导致出错。
//【所以我们应该实现一个这样的non-member函数】:
const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator(),
lhs.denomination()*rhs.denomination());
}
#2.决定上述non-member函数是non-friend函数还是friend函数的理由是
“是否必须对class内部private成员或protected成员进行访问”,
若需要,则该non-member函数应是friend函数,
若不需要,为满足最大封装性原则,该non-member函数应是non-friend函数。
____________________________________________________________________________________________________________________________________
条款25:考虑写出一个不抛出异常的swap函数
#1.如果swap的缺省实现码对你的class或class template提供了可接受的效率,
请使用该缺省实现版:
namespace std{
template
void swap(T&a, T&b) //std:swap的典型实现
{ //置换a和b的值
T temp(a);
a = b;
b = temp;
}
}
反之,如果因class或class template使用了pImp手法(pointer to implementation):
class WidgetImpl{
public:
...
private:
int a, b, c;
std::vector
v;
...
};
class Widget{
public:
Widget(const Widget& rhs);
Widget& operator=(const Widget&rhs)
{
...
*pImv = *(rhs.pImpl);
...
}
...
private:
WidgetImpl* pImv;
};
从而引起了效率不足,请做以下几件事来提高效率:
(1).提供一个public swap member函数:
//pImv是private成员变量,所以要从内部来swap,
//当然也可用friend,但这样的写法和STL一致
class Widget{
public:
...
void swap(Widget& other)
{
using std::swap;
swap(pImpl, other.pImpl);
}
...
};
//该swap函数保证了异常安全性和高效性,因为swap置换的是指针,对于指针
//和内置类型的置换操作绝不会抛出异常,并且还很高效。如果是对自定义类型
//执行swap函数,则会因为copy构造函数和copy assignment操作符而允许抛出异常。
(2).在你的class或template所在的namespace(如果没有,则是globe)内提供一个
non-member swap函数,并令它调用上述的swap函数,例如:
namespace WidgetStuff{
...
template
class Widget {...}
...
template
void swap(Widget
& a, Widget
& b) { a.swap(b); } }
(3).如果正在编写的是一个class(而非class template),为你的class特化std::swap,
并让它调用你的swap member函数,例如:
namespace std{
template<>
void swap
(Widget& a, Widget& b)
{
a.swap(b);
}
}
//=======================================================================
// 理由:
// 好处是即使客户不慎直接调用了std::swap,至少也能获得一个全特化版的swap函数,
// 另外,C++只运行class template偏特化,但不允许function template的偏特化,
// 因此无法通过编译(虽然某些编译器错误的接受了它)。
//=======================================================================
(4).如果你调用swap,请使用using声明式,以便让std::swap在函数中曝光可见,从
而在swap直接书写调用时可获得如下的效率查找:
<1>.在与class相同的 namespace 中查找swap函数。
<2>.在globe坏境中查找swap函数。
<3>.在namesapce std中查找全特化swap函数(如果是class而非template,并且予以了实现)
<4>.在namesapce std中查找一般swap函数。
#2.在std内进行std tem