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

以函数替换对象——108

我们来设计一个用来表现日期的class设计构造函数:

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

上面的设计似乎没问题,但是客户很容易犯下至少两个错误:
(1)他们也许会以错误的次序传递参数:
Date d(30,3,1995); //应该是“3.30”
(2)他们可能传递一个无效的月份或天数:
Date d(2,30,1995); //应该是 “3.30”
在防范“不值得拥有的代码”上,类型系统是你的主要同盟国。
现在,让我们导入简单的外覆类型来区别天数、月份和年份,然后于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(Month(3),Day(30),Year(1995));

同时我们使用类来表示一年只有12个有效月份:

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));

限制类型内什么事可做,什么事不能做——110

我们可以有以下几个办法:
(1)常见的限制是加上const。
(2)除非有好理由,否则应该尽量令你的types的行为与内置types一致。
(3)避免无端与内置类型不兼容,真正的理由是为了提供行为一致的接口。
一致性很重要,例如每个STL容器都有一个名为size成员函数,它会告诉调用者目前容器内有多少对象。

tr1::shared_ptr支持定制型删除器——111

这个可以回顾条款14,这里面新加的null shared_ptr十分有用。
任何接口如果要求客户必须记得做某些事情,就是有着“不正确使用”的倾向,因为客户可能会忘记做那件事。
比如条款13中的factory函数,它返回一个指针指向Investment继承体系内的一个动态分配对象,为避免资源泄露,我们令factory函数返回一个智能指针:
std::tr1::shared_ptr<Investment> createInvestment();
返回tr1::shared_ptr的确让接口设计者得以阻止一大群客户犯下资源泄露的错误。
假设class设计者期许那些“从createInvestment取得Investment* 指针”的客户将该指针传递一个名为getRidOfInvestment的函数,而不是直接在它身上动刀(使用delete)。这样一个接口有开启通往另一个客户错误的大门,该错误是“企图使用错误的资源析构机制”(也就是拿delete替换getRidOfInvestment).
createInvestment的设计者可以针对此问题先发制人:返回一个“将getRiOfInvestmen绑定为删除器“的tr1::shared_ptr.
tr1::shared_ptr提供的某个构造函数接受两个实参:一个是被管理的指针,另一个是引用次数变成0时将被调用的“删除器”。这启发我们创建一个null tr1::shared_ptr并以getRidOfInvestment作为其删除器:

std::tr1::shared_ptr<Investment>
    pInv(static_cast<Investment*>(0),
    getRidOfInvestment);

因此,如果我们要实现creaetInvestment使它返回一个tr1::shared_ptr并夹带getRiOfInvestment函数作为删除器,代码看起来像这样:

std::tr1::shared_ptr<Investment> createInvestment()
{
std::tr1::shared_ptr<Investment> retVal(static_cast<Investmnet* >(0),getRidOfInvestment);
retVla=..;
return retVal;
}

总结——113

(1)好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质。
(2)“促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容。
(3)“阻止误用”的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。
(4)tr1::shared_ptr支持定制型删除其。这可预防DLL问题,可悲用来自动解除互斥锁等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值