版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/budding0828/article/details/86624927
第四章:设计与声明
条款18:让接口容易被正确使用,不易被误用
- tr1::shared_ptr允许当智能指针被建立起来时,指定一个资源释放函数(所谓的删除器deleter)绑定于智能指针身上。(auto_ptr)则不行。
//创建一个null shared_ptr<Investment> 并携带一个自定的删除器。
std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment); //getRidOfInvestment是删除器
pInv = ...; //令pInv重新指向
-
tr1::shared_ptr有一个特别好的性质是:它会自动使用它的“每个指针专属的删除器”,因而消除另一个潜在的客户错误:所谓的“cross-DLL problem”。
-
cross-DLL problem:这个问题发生于“对象在动态连接程序库DDL中被new创建,却在另一个DLL内被delete销毁”
设计class犹如设计type
宁以pass-by-reference-to-const替换pass-by-value
-
缺省情况下C++以by value方式传递对象至函数
-
pass by reference to const
bool f(const Student & s);
优点:更加高效、避免对象切割问题
- 对象切割问题
class Window{
public:
virtual void display() const; //即使是虚函数也没有作用
};
class WindowWithScrollBars: public Window{
public:
virtual void display() const;
};
void print(Window w) //不正确!参数可能被切割。如果传的是指针,效果就不一样了
{
w.display();
}
WindowWithScrollBars wssb;
print(wssb);
不论传递过来的对象是什么类型,参数w都是一个Window对象,调用的都是Window::display();
解决办法
void print(const Window& w)
{
w.display();
}
- STL的迭代器和函数对象,习惯上都是被设计为passed by value
条款21:必须返回对象时,别妄想返回其reference
- local 对象在函数退出前被销毁了
const int& func()
{
int temp = 1;
return temp; //错误
}
- 绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象
条款22:将成员变量声明为private
-
将成员变量隐藏在函数接口的背后,可以为“所有可能的实现”提供弹性。
-
一旦你将一个成员变量声明为public或protected而客户开始使用它,就很难改变那个成员变量所涉及的一切。
条款23:宁以non-member、non-friend替换member函数
-
non-member函数可允许对class相关机能有较大的包裹弹性,而那最终导致较低的编译相似度,增加class的可延伸性。
-
愈多东西被封装,我们改变那些东西的能力就愈大。愈多函数可以访问它,数据的封装性就愈低。
- 对于non-member non-friend函数,有较大的封装性,因为它不增加“能够访问class内的private成分”的函数数量。
-
可以将class和有关的操作函数放在同一个namespace(命名空间)中。
条款24:若所有参数皆需类型转换,请为此采用non-member函数
class Rational
{
public:
Rational(int numerator=0, int denominator=1); //non-explict
...
const Rational operator* (const Rational& rhs) const; //将operator* 写成成员函数的写法
private:
int numerator;
int denominator;
}
Rational oneHalf(1,9);
Rational result = oneHalf * 2; //正确,但是当构造函数是explict时错误
result = 2 * oneHalf; //错误
使用非成员函数进行转换
class Rational
{
...
}
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator());
}
条款25:考虑写出一个不抛异常的swap函数
将std::swap针对Widget特化
namespace std{
template<>
void swap<Widget>(Widget& a, Widget& b)
{
swap(a.pImpl, b.pImpl);
}
}
//调用
class Widget{
public:
...
void swap(Widget& other)
{
using std::swap;
swap(pImpl, other.pImpl);
}
private:
WidgetImpl* pImpl;
}