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

假设正在为一个表示时间日期的类设计构造函数:

class Date {
public:
 Date(int month, int day, int year);
 ...
};
Date d(30, 3, 1995); // 糟糕! 应该是 “3, 30” , 而不是 "30, 3"
Date d(2, 30, 1995); // 糟糕! 应该是 "3, 30" , 而不是 "2, 30"

引入新的类型,可以避免许多客户的错误:

struct Day {
    explicit Day(int d) :val(d) {}
    int val;
};
struct Month {
    explicit Month(int d) :val(d) {}
    int val;
};
struct Year {
    explicit Year(int d) :val(d) {}
    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)); 	// 正确, 参数类型正确

 只有12个有效的月份值,Month类型应该反映这一点。一种方法是使用枚举来表示月份,但枚举的类型安全性不高。例如,枚举可以像int一样使用(参见条款2)。更安全的解决方案是预先定义所有有效月份的集合:

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

任何要求客户小心的接口都容易被错误使用,因为客户可能会忘记:

Investment* createInvestment(); // 来之条款13; 为简单起见,省略了参数

这会导致至少两种类型的客户错误:没有删除指针,以及多次删除同一个指针。
一个更好的接口决策是,让工厂函数返回一个智能指针:

std::shared_ptr<Investment> createInvestment();

// 错误!尝试使用自定义删除器创建一个null shared_ptr;
std::shared_ptr<Investment> pInv(0, getRidOfInvestment);

std::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment); // 可以

std::shared_ptr<Investment> createInvestment()
{
    std::shared_ptr<Investment>    retVal(static_cast<Investment*>(0),getRidOfInvestment);
    retVal = ...; // 让retVal指向正确的对象
    return retVal;
}

shared_ptr可以解决“跨DLL问题”。当在一个DLL中使用new创建对象,但在另一个DLL中delete时,会出现此问题。shared_ptr避免了这个问题,因为它的默认删除器来自创建shared_ptr的同一个DLL中。例如,如果Stock是Investment的派生类:

std::shared_ptr<Investment> createInvestment()
{
 return std::shared_ptr<Investment>(new Stock);
}
  • 好的接口易于正确使用,而不容易错误使用。应该在所有的接口中努力实现这些特性。
  • 促进正确使用的方法包括:接口的一致性和与内置类型的行为兼容性。
  • 防止错误的方法包括创建新类型、限制类型上的操作、限制对象值以及消除客户资源管理责任。
  • shared_ptr支持自定义删除器。这防止了跨dll问题,可以用来自动解锁互斥锁(见条款14)等
  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值