条款18
让接口容易被正确使用,不易被误用
tr1::shared_ptr缺省删除器来自“tr1::shared_ptr”诞生所在的dll
std::tr1::shared_ptr<Investment> createInvestment()
{
std::tr1::shared_ptr<Investment> reVal(static_cast<Investment*> (0),getRidofInvestment);//指定删除器
reVal = ...;
return reVal;
}
条款19
设计class犹如设计type
条款20
宁以pass-by-reference-to-const替换pass-by-value
以reference传递,可避免slicing问题
以by value传递无多态
内置类型以pass by value更高效
STL迭代器和函数对象pass by value
条款21
必须返回对象时,别妄想返回其reference
在函数中new以后返回对象引用,会出现的问题:w=x*y*z;-->资源泄漏
(如果不返回引用,同样会造成泄漏,所以不要返回一个local对象的引用)
条款22
将成员变量声明为private
不封装意味不可改变!成员变量的封装性与“成员变量的内容改变时所坏量的代码数量”成反比。
条款23
宁以non-member,non-friend替换member函数
std命名空间中的多个头文件
条款24
若所有参数皆需要类型转换,请采用non-member函数
隐式转换,
const Rational operator*(const Rational& rhs) const;
Rational oneHalf(1, 2);
result = oneHalf * 2; // 正确,2被隐式转换为Rational(2,1)
//编译器眼中应该是这样:const Rational temp(2); result = oneHalf * temp;
result = 2 * oneHalf; // 错误,2,可不被认为是Rational对象;因此无法调用operator*
可见,这样并不准确,因为乘法(*)应该满足交换律,不是吗?
所以,支持混合式算术运算的可行之道应该是:让operator*成为一个non-member函数,允许编译器在每一个实参上执行隐式类型转换:
class Rational
{
... // contains no operator*
};
const Rational operator*(const Rational& lhs, Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
Rational oneFourth(1, 4);
Rational result;
result = oneFourth * 2;
result = 2 * oneFourth; //这下两个都工作的很好,通过隐式转换实现
成员函数的方面是非成员函数,而不是友元函数。
可以用类中的public接口实现的函数,最好就是非成员函数,而不是采用友元函数。(引用点击打开链接)
条款25
考虑写一个不抛出异常的swap函数
template<>void swap<widget>(Widget&a,Widget&b)
{
swap(a.piml,b.piml);
}
template<>表示它是std::一个全特化,<widge>表示这个特换版本针对T是Widget,但此版本由于访问权限问题无法通过编译
下面是一种正确方式:
class Widget
{
public:
void swap(Widget&other)
{
using std::swap;
swap(pImpl,other.pImpl)
}
private:
WidgetImpl * pImpl;
};
namespace std
{
template<>
void swap<Widget>(Widget & a,Widget & b)//特化
{
a.swap(b);
}
}
对于模板
template <class T>
class WidgetImpl
{
...
};
template <class T>
class Widget
{
...
};
namespace std
{
template<class T>
void swap<Widget<T>>(Widget<T> & a,Widget<T> & b)//错误,偏特换function template不允许,class template偏特化可以。
{
a.swap(b);
}
}
偏特化是什么意思:?
模板的偏特化是指需要根据模板的某些但不是全部的参数进行特化
namespace std
{
template<class T>
void swap(Widget<T> & a,Widget<T> & b)//也是不合法的,std不可以添加新的templates
{
a.swap(b);
}
}
解决方法:
namespace WidgetStuff
{
template<class T>
class Widget{...};
template<class T>
void swap(Widget<T> & a,Widget<T> & b)
{
a.swap(b);
}
}
书中原话(太晕了!!)
template<class T>
void doSomething(T&obj1,T&obj2)
{
using std::swap;
...
swap(obj1,obj2);
}
一旦编译器看到对swap的调用,它们便查找适当的swap并调用。c++的名称查找法则确保将找到global作用域或T所在命名空间内的任何T的专属swap函数,如果T是Widget并位于命名空间WidgetStuff内,编译器会使用“实参取决之查找规则”找出WidgetStuff内的swap。如果没有T专属swap,编译器使用std的swap,using声明式。然而即便如此编译器还是比较喜欢std::swap的T专属特化版本,而非template,所以如果你已经针对T将std::swap特化,特化版本将被调用。