条款十八:让接口容易被正确使用,不易被误用
如果我们设计一个日期类,可能会写成如下的模样
class Date{ public: Date(int month, int day, int year); … };
这个构造函数貌似没有问题,但是她却无法阻止用户输入错误的数据。比如用户可能会把Date(3,30,2015)写成Date(30,3,2015)。
所以说其实当你设计的程序需要假定用户都能按你想像来进行操作的话,这个程序就存在隐患。
一种好的改善方式是让用户知道,传参的时候传递的是哪些内容。我们可以用新的类来代替int
class Month{ private: int m_month; public: explicit Month(int month): m_month(month){} }; class Day{ private: int m_day; public: explicit Day(int day): m_day(day){} }; class Year{ private: int m_year; public: explicit Year(int year): m_year(year){} }; class Date{ private: Year m_year; Month m_month; Day m_day; public: Date(Year year, Month month, Day day): m_year(year), m_month(month), m_day(day){} }; int main(){ Date date(Year(2013), Month(5), Day(28)); }
这样做,一来用户可以明确输入的数据内容,二来,可以在类内添加约束比如
explicit Month(int month): m_month(month){assert(m_month >= 1 && m_month <= 12);}
这样输入非法数据就会报错。
另一种避免用户误用的方式是让编译器对不正确的使用方式加以阻止,比如
const Object operator* (const Object& a, const Object& b);
就可以避免用户写出a = b*c这样的错误代码
还有一点就是要“尽量令你的自定义类型的行为与内置类型行为一致”。打个比方,不要重写了操作符*,却在内部定义+的功能。
最后一点,在管理资源的时候,最好使用专门的资源管理类,比如简单工厂函数的返回值,要设为shared_ptr或者auto_ptr。