类和继承(一):类设计者的核查表

构造函数

  • 简单的类,结构就是接口,不需要构造函数

数据成员私有

  • 阻止类的使用者私自改动
  • 提供相应接口,供使用者执行修改或访问等操作

无参构造函数

  • 声明对象数组必需

初始化数据成员

  • 每个构造函数都要负责为所有的数据成员设置经过明确定义的值

  • 除非该数据成员在类的对象存在一定时间后才有意义或其它特殊情况

析构函数

  • 该类分配了不会被成员函数自动释放的资源(动态内存)时必需

虚析构函数

  • 类B派生的子类D,若可能对D类型对象的B*指针执行delete表达式时必需

  • 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class B {
string s;
};
class D : public B {
string t;
// virtual ~B() {};
};
int main() {
B* bp = new D; // no problem
delete bp; // unless B has a virtual destructor
// or the wrong dstructor would be called
}

拷贝构造函数

  • 当复制类的对象并非复制其数据成员和基类对象时必需

若不想使用者能够复制类的对象,就声明复制构造函数(赋值操作符)为私有的

赋值操作符

  • 当赋值类的对象并非复制其数据成员和基类对象时必需

考虑赋值给对象本身的情况

  • 例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class String {
public:
string& operator=(const String &s);
private:
char *data;
};
String& String::operator=(const String& s) {
if (&s != this) { // do nothing with self-assignment
delete [] data; // delete old array
data = new char[strlen(s.data) + 1];
strcpy(data, s.data);
}
return *this;
}

若不想使用者能够设置类中的对象,就将赋值操作符私有化

析构函数、拷贝构造函数、赋值操作符= 三者通常为同时必需的

  • 关系操作符
    • 类逻辑上支持相等操作则提供 operator==operator!=
    • 类具有某种排序关系则提供余下的关系操作符(<, >, <=, >=)

拷贝构造函数和赋值操作符的参数类型加上const

  • X::X(const X&) X::operator=(const X&)

函数的const引用参数

  • 除非函数用来改变参数的值否则应为const引用

  • 例如: Complex operator+(const Complex& x, const Complex& y);

适当声明成员函数为const

  • 成员函数不用修改它的对象时

const对象只能使用声明为const的函数

设计理念

C++不可能自动处理所有这些事情(难以保证做得对)
始终加入的话增加太多的额外负担,开销过大
例如,若给所有类自动添加一个虚析构函数,当类较小时开销明显
作为变通方法,让编译器指出什么时候类该有什么必需的


《C++沉思录(Cplusplus Thinking)》笔记