如何专业的定义一个class?这里记录一下自己的checklist
关于构造函数的注意点
a. 构造函数声明为explicit,避免隐式转换
b. 考虑禁用复制构造函数、赋值函数
c++中,默认对于类会产生以下成员函数(如果你没有定义的话,这通常是不可控的)
class Empty() {
public:
Empty();
~Emtpy();
Empty* operator&(); //取址运算符
const Empty* operator&() const; //取址运算符 const
private:
Empty(const Empty &); //赋值构造函数
Empty& operator=(const Empty &); //赋值运算符
}
这里取址函数不用多说,关键是赋值相关的两个函数,默认是浅copy的,所以还是禁用,参考析构函数注意点
c. 构造函数尽管可以抛出异常,但没有返回值;所以可以考虑单独实现一个Init函数作为补充
采用初始化列表而不是赋值初始化成员变量,有两种情况你必须这样做:
a. const \ reference的成员
b.派生类的方法中需要调用基类的构造函数
Base(int x):m_x(x) {
}
Derived(int x) : Base(x) {
}
成员函数如果不改变类的状态,声明时后加const
尽可能将成员变量private更可控,更透明
以非member 方法代替需要多个对象的member组合功能的实现
考虑Law of Demeter,适当做一个权衡,少一些wrapper或中介类
关于析构函数的注意点
a. 一个类要被继承时(其往往含有虚函数要多态),要提供虚析构函数,否则存在下面的情况:
Base *pb = new Derived();
delete pb;//这里就不会调用派生类的析构函数,尽管pb的虚指针指向了派生的虚表,但其虚表中没有虚析构函数,造成派生对象资源泄露
b.只要有基类的析构函数是虚拟的,那么所有的派生类不管是否明确的写了虚拟析构函数,派生了的析构函数可以认为一定是虚拟的。如同类的虚指针,所有派生的默认都有
c.在析构中不要抛出exception,否则实现此异常接口
如果类含有指针成员和引用成员,则该类型通常需要实现析构函数(这里不一定是虚的,但是需要考虑清理内存)
更进一步,一旦实现了析构函数,就进而需要实现实现拷贝构造函数与拷贝复制函数,否则,需要明确拒绝(或者,仅仅一个理由:做副本有没有道理,见这里第一个条款)