-
三法則
鎖定
- 中文名
- 三法則
- 外文名
- Rule of Three
- 學 科
- 計算機語言
- 定 義
- 以設計的基本原則而制定的定律
- 組 成
- 析構函數、複製構造函數
- 提出者
- 馬歇爾·克來恩
三法則簡介
三法則這個專有名詞是由馬歇爾·克來恩於1991年創立的,假設類有用到RAII,可以不必定義析構函數。 因為隱式生成的構造函數與賦值運算符可以很容易地複製類內所有的數據成員,當數據成員是指針類型時,指針地址會隨着類而跟着被複制。要注意的是,直接地複製指針地址是一項非常危險的動作,所以只要類有封裝指針類型的數據結構,或是類有封裝外部引用的數據成員,例如指針類型的數據成員,程序員應該為此而定義顯式的複製構造函數與賦值運算符。RAII全稱為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 <iostream> #include <limits> // 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