五:设计与声明

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

我们的目标是:
如果客户企图使用某个接口而没有获得他所预期的行为,这个代码就不该通过编译;如果代码通过了编译,它的作为就该是客户想要的。

我们来看一个例子,设计一个表现日期的类:

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

看着是不是觉得还行,但它的客户至少会犯下两个错误:

  1. 以错误的次序传递参数
    Date d(30, 3, 1995);
    
  2. 传递一个无效的月份或天数
    Date d(2, 30, 1995); //2.30,本来想3.30,但是键盘上2和3很近啊
    

许多客户端错误可以通过导入新类型而获得预防:

struct Day{
explicit Day(int d) : val(d){}
int val;
};
//Month和Year类似,不再赘述
class Date{
public:
    Date(const Month& m, const Day& d, Const Year& y);
}
//这时候,用户就只能这么写了
Date d(Month(3), Day(30), Year(1995)); //虽然麻烦,但是避免了参数顺序搞错,也更明了

一旦正确的类型就位,限制它的值也就很自然,比如月份,我们可以用enum来列举,但是它不是类型安全的,因为它可以被当作int来使用,我们的方法是条款四,用函数替换对象(避免non-local static对象初始化出现问题):

class Month{
public:
    static Month Jan(){return Month(1);} //静态函数,通过构造函数返回Month对象,
    ...
private:
    explicit Month(int m);
};
Date d(Month::Jan(), Day(30), Year(1995)); //完美

预防客户错误的另一个方法是:限制类型内什么事可做,什么不能做。例如条款三“以const修饰operator*的返回类型”,不准给返回值赋值

一般性准则:尽量让types的行为与内置类型一致

任何接口,如果要求客户必须干嘛,就很有可能gg,因为客户会忘记啊,例如条款十三:

Investment* createInvestment(); //要求客户必须记得删除指针

客户会犯两种错误:忘记删除指针和删除超过一次

更好的设计:

shared_ptr<Investment> createInvestment();

还有一点小问题,有时候我们要自定义删除器,因为我们不想删除它,只是要对它进行一些操作,假设这个操作放在getridofInvestment函数中,那么可以在定义智能指针的时候将其作为删除器,也就是在引用计数为0时调用该删除器:

shared_ptr<Investment> pInv(static_cast<Investment*>(0), getridofInvestment);

使用自定义删除器还可以消除cross-DLL problem

条款十九:设计类犹如设计类型

C++ 就像其他OOP语言一样,当你定义一个新class时,也就定义了一个新的type,所以你要谨慎地研讨class的设计

条款二十:宁以常量引用传递替换值传递

一切为了节省,少了拷贝,也就少了拷贝构造函数和析构函数等等的花费
除了节省之外,引用还可以实现多态,避免对象被切割,但是值传递就不行了:

class Window{
public:
    virtul void display() const;
};
class WindowNew : public Window{
public:
    virtul void display() const;
};

现在假设你要写个函数打印,下面是错误示范:

void print(Window w){
    w.display; //只会打印基类,因为w是基类啊
}

正确示范:

void print(consty Window& w){
    w.display; //多态,传进来是什么对象,就打印什么
}

引用在底层是指针实现的,所以内置类型和STL的迭代器和函数对象一般用值传递也比较好

小结:

  • 尽量以常量引用传递替换值传递,前者通常比较高效,且可避免切割问题
  • 以上规则不适合内置类型和stl的迭代器和函数对象

条款二十一:必须返回对象时,别妄想返回其引用

适用于返回的对象开始不存在,在函数内缔造,你要是不通过返回对象拷贝出来,它就会被释放掉,正因为会被释放,所以不能返回引用,不然你引用的东西被释放了,这个引用就gg了

条款二十二:将成员变量声明为private

为了赋予客户访问数据的一致性(都通过带括号的函数访问),封装性等等好处

条款二十三:宁以非成员函数、非友元函数替换成员函数

增加封装性,包裹弹性和机能扩充性

条款二十四:若某个函数的所有参数都需要类型转换,请为此采用非成员函数

因为this所指的隐喻参数没办法隐式转换

全部评论

相关推荐

01-15 17:34
保定学院 Java
数学转码崽:学历没优势就得卷项目和实习啊,但是我看了一下你这个项目,什么雪花算法,搜索引擎,Docker,minio这些都属于通用的东西啊,根本不算亮点,没有任何业务相关性。 还有第二个看到统一鉴权,分片上传估计面试官都不想看了。连我一个偶尔刷刷牛客简历的都看多了,面试官估计早都看吐了。。。 秋招结束了,就尽量找找中小厂吧,毕竟你现在转行已经没时间了,高低有一段实习经历
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客企业服务