Effective C++ 第四章:设计与声明

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/budding0828/article/details/86624927
今日推荐