设计良好的class如同内置类型(type)一样,接口自然,目的明确。
在设计class之前,设计者必须扪心自问:
新type的对象应该如何被创建和销毁?
该问题的回答决定了构造函数、析构函数、内存分配和释放函数对象的初始化和赋值有何区别?
该问题的回答决定了构造函数与赋值操作符的的行为。尤其需要注意的是,“初始化”、“赋值”是完全不同的概念,它们调用了不同的函数。新type的对象如果被pass by value,意味着什么?
具体实现方式可参考Effective C++ 14;新type的合法值是什么?
对于成员变量而言,可能仅有某些数值集有效。这些数值集决定了class的约束条件,同时也决定了setting函数(构造、赋值等)必须进行的错误检查,同时,它也影响函数抛出的异常。新type需要配合某个继承体系吗?
如果当前type继承自某些class,那你必然受到了那些class设计的束缚,尤其是virtual或者non-virtual成员函数的影响。(详见Effective C++ 34/36/37/38)
如果你允许别的类继承该type,那请谨慎考虑析构函数是否需要virtual。(Effective C++ 8)新type需要什么样的转换?
如果你允许T1被隐式转换为T2,就必须在T1内写一个类型转换函数,或者为T2写一个non-explicit-one-argument(可被单一实参调用)的构造函数。(More Effective C++ 5)
如果你只允许explicit构造函数存在,就必须撰写显式类型转换函数,并且禁止定义类型转换操作符或者non-explicit-one-argument构造函数。新type需要哪些操作符和成员函数?
该问题的回答决定了class中需要声明的函数,其中有一些是成员函数,有些则不应该是。(Effective C++ 24,25,47)新type应当明确禁止哪些函数?
该问题的回答决定了class中哪些函数需要声明为没有定义的private成员函数。(Effective C++ 6)谁会试图使用新type的成员?
该问题的回答决定了成员函数的可见性,并且也决定了friend。type的一般化程度如何?
如果一般化的程度足够高,或许我们不应该定义一个class,而是应该定义一个class template。是否真的需要一个新type?
如果你只是想增加了一个derived class为原有的class添加功能,先试试看能不能用一些non-member函数或者templates解决。
每一次写下class之前请默读本章所有问题。