您的位置:首页 > 编程语言 > C语言/C++

C++的Rule of Three

2014-02-19 21:18 253 查看
Rule of Three是国外的人提出来的一条法则,可运用于很多行业,在他们看来,数字3代表稳定,也让人觉得舒服。可以把它理解为三者法则,国内也有人翻译为三强鼎立法则。

C++中的Rule of Three指的是析构函数、拷贝构造函数和重载赋值函数三者之间的关系,具体指的是在一个类当中当你需要显式地定义这三个函数中的任意一个时,你应该同时显式地定义其它两个,也就是说这三个函数要么都不定义,要么都要定义。这一规则在C++标准中不是强制性的,但作为优秀的程序员,应谨记这一规则。下面我们通过程序来讲解。

首先来看这样一段代码:

class Rectangle {
int m_width, m_height;
public:
Rectangle(int w = 0, int h = 0) :
m_width(w), m_height(h) {
}
};

void trectangle() {
Rectangle first;
Rectangle second(4, 3);
Rectangle third(second);
first = third;
}

这段代码写了一个简单的类,测试函数trectangle中演示了几种对象的构造方法,对象third的构造调用了拷贝构造函数,最后对first对象的赋值则调用了重载赋值函数。这里的情况是我们的类Rectangle既没有定义析构函数,也没有定义拷贝构造和重载赋值函数,编译器会为我们自动生成,自动生成的代码可能是这样子的:

~Rectangle() {
}
Rectangle(const Rectangle &other) {
m_width = other.m_width;
m_height = other.m_height;
}
Rectangle &operator=(const Rectangle &other) {
m_width = other.m_width;
m_height = other.m_height;
return *this;
}
编译器自动生成的代码可以满足要求,所以这里我们不必显式地定义。

通常析构函数、拷贝构造函数和重载赋值函数中我们第一个需要定义的是析构函数,而需要定义析构函数的情形是类的构造函数中存在相关资源占用, 我们需要在析构函数中释放,比如这样一个例子:

class ByteArray {
char *m_data;
public:
ByteArray() {
m_data = new char[32];
}
ByteArray(const char *data, int size) {
m_data = new char[size];
strncpy(m_data, data, size);
}
~ByteArray() {
delete[] m_data;
}
char *data() { return m_data; }
};

void tbytearray() {
ByteArray first;
ByteArray second("hello, world", 8);
ByteArray third(second);
first = third;
}
以上代码中ByteArray类作为一个简单的容器类,其类属性为一个指针,需要做动态内存分配,所以我们需要显式地定义析构函数。这不是关键,关键在于此时测试函数tbytearray中third对象的构造和对first对象的赋值,它们分别调用拷贝构造函数和重载赋值函数,因为没有显式地定义,编译器将帮我们生成,而生成的代码将会是这样子的:

ByteArray(const ByteArray &other) {
m_data = other.m_data;
}
ByteArray &operator=(const ByteArray &other) {
m_data = other.m_data;
return *this;
}
这里很明显将出现问题,编译器生成的代码只是简单的做值的拷贝,而对于指针,不能这样简单的赋值,这种简单赋值也称为浅拷贝,我们要做的是深拷贝,即要将指针所指的内容拷过去,并且新的对象要重新申请内存,不然将有两个对象引用同一块内存区,在析构时同一块内存区将被释放两次,这是不允许的,所以我们要自己实现拷贝构造和重载赋值函数。

至此我们应该看到了Rule of Three所体现的内涵,而这种细节问题是很多初学者容易忽视的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: