C++设计与声明——让接口容易被正确使用

c/c++

浏览数:214

2019-9-2

一个简答易错的例子

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

一年后使用这个接口的时候,写了Date d(15,10,2015)或者Date d(2015,10,15),准确的应该是Date d(10,15,2015),欧,多么低级的错误,花了我一个早上的时间去调试这个bug。

解决的方法

  • 为参数声明自定义类型
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);    //wrong
Month m(10);
Day m(15);
Year y(2015);
Date(y, m, d);          //wrong
Date(m, d, y);          //right

这样子声明类型会很麻烦,但是对“接口被误用”却又神奇的疗效

  • 使用预先定义的类
class Month
{
public:
    static Month Jan()
    {
        return Month(1);
    }
    ...
private:
    explicit Month(int m);
    ...
};

通过函数返回我们需要的月份,保证参数的正确性。

PS:上面使用函数返回,是为了保证使用的月份实例已经初始化

  • 自定义类型与内置类型保持一致

常见的方法有:加上const。再来一个易错的例子

class INT
{
public
    INT(int);
    INT opeaator=(INT);
    INT operator*(INT);
    int val;
};
    if(a*b = c)
    {...}

我们重新定义了系统的int类型,却发现,在a * b = c成功地通过了编译阶段,这个时候要想不进入if下的程序块真的是难上加难,这很明显违背我们的初衷。假如operator返回的是const,那么就会限制a b = c的执行。其实,这只是与内置类型的int符合罢了。所以,自定义的type应该尽量内置类型保持一致,除非我们有个好理由(其实一般我们也找不到这种理由)。

  • 保持接口一致化

假如string使用Length,List使用size返回内部的对象个数,你是不是每次使用的时候都要考虑一下要使用Length还是size?假如不想自己的心灵饱受折磨,请保持功能一致的接口使用方法一致。

  • 在客户之前预防客户的错误

假如createInvestment()返回一个Investment类型的指针给客户,谁也无法保证客户使用完了会正确地释放内存。所以较佳的做法是,先发制人,强迫客户使用智能指针,将返回值修改为std::tr1::share_ptr< Investment >createInves()给客户,这基本消除了发生内存泄露的可能性。

假如客户希望通过getRidOfInvestment()来删除指针,但却希望客户自己完成这件事,那又多了一个通往错误的大门。我们可以在返回智能指针前就先指定好删除器,以免客户遗忘。

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

上面的例子中,就算用户忘记了释放内存,最后智能智能share_ptr也会根据getRidOfInvestment正确地释放,从而减少了内存泄露的可能性。

实际上,使用了share_ptr的好处不仅仅如此。当使用了dll的时候,假如在一个dll中获得了指针,在另一个dll中依然能通过原来的dll对指针进行删除。从而用户无需在意cross dll problem的问题。

作者:随梦