所谓软件设计,是“令软件做出你希望它做的事情”的步骤和做法,通常以颇为一般性的构想开始,最终演变成十足的细节,以允许特殊接口的开发,这些接口而后必须转换为C++声明式。本章将以接口开始讲解软件设计和声明,主要包括以下几个部分:
当接口的参数是一个类型时,客户可能会以错误的次序传递参数,比如以下表现日期的class设计构造函数:
class Date{ public: Date(int month, int day, int year); ... }
导入外覆类型:
struct Day{ explicit Day(int d):val(d){} //声明为explicit的构造函数不能在隐式转换中使用 int val; }; struct Month{ explicit Month(int m):val(m){} //struct中有构造函数,第一次见 int val; }; struct Year{ explicit Year(int y):val(y){} int val; }; class Date{ public: Date(int month, int day, int year); ... } Date d(30, 3, 1995); //错误! Date d(Month(3), Day(30), Year(1995));
常见的限制是加上const,比如以const修饰operate*的返回类型可以阻止客户因为用户自定义类型而犯错:
if(a*b=c)//原意其实是要做一次比较动作
如果a和b都是int,那么对a*b赋值并不合法,所以如果是你自定义的types,应该让你的types也有相同的表现。
STL容器的接口十分一致,这使得它们非常容易被使用。比如每个STL容器都有一个名为size的成员函数,它会告诉调用者目前容器内有多少对象。
任何接口如果要求客户必须记得做某些事情,就是有着“不正确使用”的倾向,因为客户可能会忘记做那件事情。比如:
BaseCamera* createCamera();//简化了参数
客户需要删除指针,同时不能删除同一个指针超过一次。我们可以用智能指针shared_ptr,但客户忘记用智能指针怎么办?较佳接口的设计原则是先发制人,令工厂函数返回一个智能指针:
shared_ptr<BaseCamera> createCamera();
当指针引用次数为0时,会删掉指针,这不是我们想要的结果,需要指定指针的删除器为Close。我们可以先发制人,返回一个绑定删除器的shared_ptr。
shared_ptr<BaseCamera> createCamera(){ shared_ptr<BaseCamera> p(satic_cast<Basecamera*>(0), Close);//构造函数要求第一个参数必须是指针,所以利用cast转型。创建一个null shared_ptr指针,并指定删除器 p = ...; //使p指向正确对象 return p; }
shared_ptr有一个很好的性质:它会自动使用它的“每个指针专属的删除器”,因而消除另一个潜在的客户作用:所谓的“cross-DLL problem”。这个问题发生于对象在dll中被new创建,在另一个dll中被delete销毁。在许多平台上,这一类“跨dll只new/delete成对运用”会导致运行期错误