条款18(一):让接口容易被正确使用,不易被误用

版权声明:仅供参考与学习交流 https://blog.csdn.net/lym940928/article/details/81592888

条款18:让接口容易被正确使用,不易被误用

Make interferences easy to use correctly and hard to use incorrectly.
本章分为两个部分。

接口

接口,是C++之本。function接口、class接口、template接口…每一种都是与代码进行交互的手段。

想要开发出一个“容易被正确使用,不易被误用”的接口,首先就需要明白使用这样的接口可能会产生怎样的错误?
举个例子,假设我们为一个用来表示日期的class设计构造函数:

class Date {
public:
    Date(int month, int day, int year);
    ...
};

虽然这样定义的构造函数乍一看没什么问题,但其实在调用时,却可能会产生以下两个错误:
(1)错误的传递参数次序:

Date d(30, 3, 1995);    //把月和日传递反了

(2)传递一个无效的月份或天数:

Date d(2, 30, 1995);    //二月有30号??

想要解决这样的问题,类型系统(type system)是一个关键办法。我们使用外覆类型(wrapper type)来区别这样的天数、月份和年份,然后在Date构造函数中使用这些类型:

struct Day {
    explicit Day(int d) : val(d) { }
    int val;
};

struct Month {
    explicit Month(int m) : val(m) { }
    int val;
};

struct Year {
    explicit Year(int y) : val(y) { }
    int val;
};

class Date {
public:
    Date(const Month& m, const Day& d, const Year& y);
    ...
};

Date d(30, 3, 1995);        //错误的类型!
Date d(Day(30), Month(3), Year(1995));  //错误的类型!
Date d(Month(3), Day(30), Year(1995));  //正确了!

以函数替代对象

当我们确定好类型的定义,限制它们的取值也是非常重要。比如,月份的取值只能是1-12。
方法之一,就是利用enum表现月份。不过enum并不具备类型安全性。因此,比较安全的解法是预先定义所有有效的Months:

class Month {
public:
    static Month Jan() { return Month(1): }  //函数,返回有效的月份
    static Month Feb() { return Month(2); }
    ...
    static Month Dec() { return Month(12);}
    ...    //其他的成员函数
private:
    explicit Month(int m)   //阻止生成新的月份
    ...
};

Date d(Month::Mar(), Day(30), Year(1995));

预防错误的另一种方法,限制类型内什么事情可以做,什么不可以做。常见的限制是加上const。在前面的条款3只,就对const的作用进行了说明。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页