三法则

科技工作者之家 2020-11-17

三法则(Rule of Three)在C++里,它是一个以设计的基本原则而制定的定律。它的要求是,假如类有明显定义下列其中一个成员函数,那么程序员必须写入其他两个成员函数到类内,也就是说下列三个成员函数缺一不可:析构函数、复制构造函数、赋值运算符。上述三个函数是特别的成员函数,假如程序员没有自行定义或宣告这三个函数,编译器会自动地创建他们并且编译到应用程序内。然而,如果程序员仅定义其中一个,其余两个函数仍然会由编译器自动产生,这种混杂的情况非常容易产生程序员难以预期的错误。三法则的存在,正是提醒程序员避免那样的陷阱。

简介三法则这个专有名词是由马歇尔·克来恩于1991年创立的,假设类有用到RAII,可以不必定义析构函数。 因为隐式生成的构造函数与赋值运算符可以很容易地复制类内所有的数据成员,当数据成员是指针类型时,指针地址会随着类而跟着被复制。要注意的是,直接地复制指针地址是一项非常危险的动作,所以只要类有封装指针类型的数据结构,或是类有封装外部引用的数据成员,例如指针类型的数据成员,程序员应该为此而定义显式的复制构造函数与赋值运算符。AII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。RAII源于C++,在Java,C#,D,Ada,Vala和Rust中也有应用。1984-1989年期间,比雅尼·斯特劳斯特鲁普和安德鲁·柯尼希在设计C++异常时,为解决资源管理时的异常安全性而使用了该用法,后来比雅尼·斯特劳斯特鲁普将其称为RAII。RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

组成析构函数

析构函数(Destructordtor)在面向对象程序设计里是一个方法,当对象的生命周期结束时,它会自动地被调用运行1。它最主要的目的在于,清空并释放对象先前创建或是占用的存储器资源。析构函数的整体使用概念关键在于RAII。一个具备垃圾回收机制的编程语言,无法确保析构函数是否会被运行,通常这类的编程语言不属于RAII的范围内。这类的编程语言,只要经由某个适当的函数,通常会调用Dispose()函数,做调用的动作,那么它一定会从现有资源释放对象。与使用垃圾回收机制的Finalize()相比,建议使用析构函数是释放资源的适当做法。

复制构造函数

复制构造函数(Copy constructor)是C++编程语言中的一种特别的构造函数,习惯上用来创建一个全新的对象,这个全新的对象相当于已存在对象的副本。这个构造函数只有一个参数(引数):就是用来赋值对象的引用(常用const修饰)。构造函数也可以有更多的参数,但除了最左第一个参数是该类的引用类型外,其它参数必须有默认值。

类的赋值构造函数原型通常如下:Class_name(const Class_name & src);

一般来说,假如程序员没有自行编写赋值构造函数,那么编译器会自动地替每一个类创建一个赋值构造函数;相反地,程序员有自行编写赋值构造函数,那么编译器就不会创建它。当对象包括指针或是不可分享的引用时,程序员编写显式的赋值构造函数是有其必要性的,例如处理文件的部分,除了赋值构造函数之外,应该还要再编写析构函数与赋值运算符的部分,也就是三法则。

赋值运算符

在C++编程语言里,赋值运算符(assignment operator)是用等号 = 符号。就像其他的C++运算符一样,它可以作为重载。赋值赋值运算符是一个特别的赋值运算符,通常是用来把已存在的对象指定给其他相同类别的对象。它是一个特别的成员函数,如果程序员没有定义这个成员函数,那么编译器会自动地产生这个成员函数。编译器产生的代码是以单一成员进行对象赋值的动作。赋值赋值运算符,这个成员函数与赋值构造函数的相异点在于,它一定会清除目标对象的数据成员(以及确实掌控自我设值的动作),而赋值构造函数不会初始化类别的数据成员。

代码示例#ifndef _HEADER_H_ #define _HEADER_H_ // //判断是否为微软编译器#ifndef _MSC_VER #undef NULL #define NULL 0 #endif // #include #include // using std :: cin ; using std :: cout ; using std :: endl ; // //类别:方块class CCube { public : //建构子 CCube (); //含有参数的建构子 CCube ( double length , double width , double height ); //三法则:解构子 ~ CCube (); //三法则:复制建构子 CCube ( const CCube & sample ); //三法则:设定运算子 CCube & operator = ( const CCube & sample ); //设定长宽高 void setLength ( double length ); void setWidth ( double width ); void setHeight ( double height ); //取得长宽高 double getLength () const ; double getWidth () const ; double getHeight () const ; //计算体积 double getVolume () const ; protected : private : //长宽高 double m_Length ; double m_Width ; double m_Height ; }; // void PAUSE ( void ); // #endif本词条内容贡献者为:

李岳阳 - 副教授 - 江南大学

科技工作者之家

科技工作者之家APP是专注科技人才,知识分享与人才交流的服务平台。