zoukankan      html  css  js  c++  java
  • C++设计与声明——让接口容易被正确使用

    一个简答易错的例子##

    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的问题。

  • 相关阅读:
    H5性能优化
    【JavaScript 】for 循环进化史
    (四十四)通过系统Gallery获取图片
    (四十三)获取图片exif信息
    (四十二)、加载大分辨率图片到内存
    (九)JAVA设计模式之单例模式
    (四十一)Activity切换动画
    (四十)android在代码中,如何设置自定义对话框在屏幕中的位置和大小
    (三十九)android动画 Animation四大属性 详解(转载:http://www.android100.org/html/201304/25/2295.html)
    (三十八)android:windowSoftInputMode属性详解
  • 原文地址:https://www.cnblogs.com/suimeng/p/4884102.html
Copyright © 2011-2022 走看看