1. 程式人生 > >【c++語言基礎】關於C++中的不變式(invariant)

【c++語言基礎】關於C++中的不變式(invariant)

類必須實現不變式(Classes Should Enforce Invariants)

Bjarne Stroustrup: 我的基本原則式真正的類必須有一個介面,有一個隱含的不變式(invariant)

Bill Venners: 不變式(invariant)是什麼東西?

Bjarne Stroustrup: 什麼使一個物件(object)有效?是不變式(invariant)。
我以vector舉例說明。vector知道自己有n個元素(element),vector也知道自己有一個指標指向這些元素。以上兩點就是不變式(invariant)。如果vector實際上竟然有n+1個元素,就出問題了。如果vector包含的指標為0,也表示有bug。所以在定義一個類前,你必須明確什麼是不變式(invariant)

  • 類的介面必須體現了不變式(invariant)。

如果類的成員函式(member function)不能體現不變式,也許這個函式應該放到類的外面比較好。
牢記類的不變式,你就能得到一個簡潔而小的介面,易於理解和維護。

Bill Venners: 不變式(invariant)是建立類的必要條件?因為類的責任就是維護不變式(invariant)?

Bjarne Stroustrup: 說得對。

Bill Venners: 不變式就是類中的各資料間的關係。

Bjarne Stroustrup: 對。如果任何資料都可以隨意定義自己的值,就沒有必要建立類。使用結構體(structure)就行了。考慮有一個數據結構只有姓名和地址兩個欄位,如果隨便什麼字串都可以作為有效的姓名或者地址。那麼結構體(structure)就夠了。把姓名和地址作為私有成員封裝到一個類中,再提供一堆訪問私有成員的介面函式,是很愚蠢的。更愚蠢的就是再去設計一個基類,把這些介面函式設計為虛擬函式。沒有必要。

Bill Venners: 你說沒有必要是因為,資料的表示(representation)有且僅有一種。如果你要把這一種表示(representation)定義為一個函式,意味著將來你會修改表示(representation)。

Bjarne Stroustrup: 對。但是有些表示(representation)並不改變。例如整數,浮點數,複數等等。設計時你不得不做決定。

仍舊以上面的姓名和地址的資料結構為例。接下來,如果你從簡單的結構體(structure)轉向了真正的類。也許你不會把那個類的名字叫做“姓名和地址的組合類”。也許你會把那個類命名為“個人通訊錄”。然後你覺得需要確保“個人通訊錄”中的地址應該是有意義的字串,等等等等。接下來你必須考慮資料的不同表示(representation)。例如姓名欄位定義為私有資料成員嗎?是否需要定義虛擬函式?你必須做設計而不是隨意定義一些類和函式,你需要使用C++的語法來表達你的核心的設計思想,而不是簡單的定義幾個私有資料就完事了。(譯者按:原文為semantics that you are defending,字面意思是保衛你所使用的符號的意義。)

例如,建構函式(constructor)建立了環境供成員函式(member function)在其中操作資料。也就是說,建構函式(constructor)建立了不變式(invariant)。要建立不變式(invariant),你必須獲得資源。解構函式(destructor)做的事情正相反。資源可以是記憶體,檔案,鎖,socket等等。

設計簡單的介面(Designing Simple Interfaces)

Bill Venners: 你剛才說不變式(invariant)幫助你決定了什麼應該進入介面(interface)。你能進一步講一講你是如何設計介面的嗎?

  • 如果一個函式有責任維護不變式(invariant)就應該在類中。

Bill Venners: 任何使用了資料,但是不維護(defend)不變式(invariant)的操作,就不需要放在class中?

Bjarne Stroustrup:讓我舉個例子。有時候某些操作必須直接訪問資料才能完成。例如如果你要改變vector的大小,前提條件你必須能夠移動其中的元素(element),修改儲存大小的變數。如果你沒有直接修改資料的許可權,為了完成操作,你必須訪問有許可權的介面函式。但是一個在vector中查詢指定元素的操作最好不要定義為vector的成員函式。

另一個例子是日期類,修改日期類中的年月日資料的操作當然應該是類的成員函式,但是查詢下個週末的函式不應該是成員函式。我曾經看到日期類有60或者70個介面函式。介面函式直接訪問資料。也就是說,如果你修改了類的資料結構,你就必須檢查並修改所有類的介面函式。

如果日期類只有比如說10個必需的介面。你可以把其餘的50個介面建立在這10個介面之上。其餘50個介面可以放在支援庫中(supporting library)。現在這種設計思想已經被普遍接受了。甚至在java中也是如此。

過去二十年我就在鼓吹這種設計思想。但是人們就是喜歡把所有的東西都丟到類和子類中去。比如說前面那個糟糕的日期類。如果你需要一些簡單的工具操作日期,你必須繼承自那個日期類。最後一切都亂七八糟。我僅僅是想自由的組合一些工具進行簡單的操作,為什麼需要繼承呢?如果我想組合使用我的一些工具和你的一些工具,難道我需要定義一個子類,同時繼承你的日期類和我的日期類嗎?繼承引入了不必要的依賴關係。

相關推薦

c++語言基礎關於C++invariant

類必須實現不變式(Classes Should Enforce Invariants) Bjarne Stroustrup: 我的基本原則式真正的類必須有一個介面,有一個隱含的不變式(invariant) Bill Venners: 不變式(invari

C語言基礎C語言第五章

第五章 選擇結構程式設計 在C語言中選擇結構使用if語句實現的。if語句最常用的形式如下: if(條件表示式) {     語句1; } else {     語句2; } 【關係運算符及其優先順序】 什麼是優先順序:小學的時候老師常說的一句話:“先乘除後加減”。 (高,同

計算機網絡基礎數據鏈路層目錄

計算機網絡 劃分 靜態 控制 網橋 透明 回退 csma/cd 廣播 數據鏈路層知識結構 數據鏈路層組幀和透明傳輸 數據鏈路層差錯檢驗 奇偶校驗 循環冗余校驗(CRC) 海明碼 數據鏈路層可靠傳輸(ARQ協議) 停止-等待協議 回退N幀協議(GBN協議) 選擇重傳協

劍指offer二進位制1的個數java

問題描述:輸入一個二進位制數,我們記為num,計算出num中有幾個1,結果用count儲存 思路分析:如二進位制數11011,將其減1,得11010,再與原來的數做與運算 11011&11010,得11010,此二進位制數相比原二進位制數,數中的1少了一個。重複此過程,直至該數變為0

編程基礎C語言常見宏定義

ifd 轉換成 erro get 程序 運算 efi 宏定義 當前 我們在使用C語言編寫程序的時候,常常會使用到宏定義以及宏編譯指令,有的可能比較常用,有的可能並不是很常用,是不是所有的C語言宏定義以及宏指令你都清楚呢? 指令 用途詳細介紹 # 空指令,無任何效果 #i

15、C語言基礎錯誤處理、遞歸

png lose 讓我 指針 ++ 自身 actor 計算 16px C 錯誤處理 C 語言不提供對錯誤處理的直接支持,但是作為一種系統編程語言,它以返回值的形式允許您訪問底層數據。在發生錯誤時,大多數的 C 或 UNIX 函數調用返回 1 或 NULL,同時會設置一個錯

嵌入式軟體工程師面經:第一部分-C語言基礎

1、關鍵字static的作用是什麼? 這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用: 1). 在函式體,一個被宣告為靜態的變數在這一函式被呼叫過程中維持其值不變。 2). 在模組內(但在函式體外),一個被宣告為靜態的變數可以被模組內所用函式訪問,但不能被模組外

C語言基礎1-5 C語言迴圈與二維陣列

C語言迴圈與二維陣列 知識點 break與continue break:break語句在switch-case語句中是跳出。break語句在迴圈中還有另一種用法。當迴圈中遇到break語句時,立即結束迴圈,跳到迴圈體外,執行迴圈結構後面的語句 conti

應用CC語言實現行列式與矩陣的運算系統+原始碼

文章目錄 01 - 行列式和矩陣 1.1 - 行列式定義 1.2 - 矩陣定義 02 - 基本運算 2.1 - 行列式基本運算 2.2 - 矩陣基本運算

C語言基礎--測試程式實現對FPS的控制

const int FRAMES_PER_SECOND = 25; const int SKIP_TICKS = 1000 / FRAMES_PER_SECOND; DWORD next_game_tick = GetTickCount(); // GetTickCoun

HPUoj 題目1019 C語言訓練尼科徹斯定理水題,數學

1019: 【C語言訓練】尼科徹斯定理 時間限制: 1 Sec  記憶體限制: 128 MB提交: 9  解決: 5 [提交][狀態][討論版] 題目描述 驗證尼科徹斯定理,即:任何一個正整數的立

自然語言處理python的jieba分詞使用手冊

這篇文章是轉載的,但是我沒找到出處啊,宣告一下~ jieba “結巴”中文分詞:做最好的 Python 中文分片語件 "Jieba" (Chinese for "to stutter") Chinese text segmentation: built to b

C語言基礎教學——迴圈結構之for迴圈第四課

C語言中的迴圈結構分為三類: 1、for()迴圈 2、while()迴圈 3、do while()迴圈 何為迴圈:程式自動重複某幾個語句 1、for()迴圈,最常用的迴圈 語法結構: for(語句1;語句2;語句3){ 迴圈體 } 語

C語言,結構體字串的宣告採用字元指標還是字元陣列

      結構體中,字串選項是用字元陣列表示好,還是用字元指標表示好? typedef struct person{ char *name; int age; char sex[6]; }       該結構體中name用的是指標而不是陣列,所以需要給字串在堆上申

C語言 判斷一個數是是素數用函式表示

# include <stdio.h> int f(int n)  //定義函式f {     int i;     int sum=0;     if(n!=2)         {  

C語言結構體宣告冒號的使用佔位符 & C結構體的亂序初始化

有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為

C語言基礎練習題c語言試題100道前三十道

c語言試題100道(前三十道)  前三十道 //自己做的由於題幹較為模糊可能和標準答案有所差異 1. 按下述格式,從鍵盤輸入一個整數加法表示式:運算元1+運算元2,然後計算 並輸出表達式的計算結果,形式如下:運算元1+運算元2=計算結果。 2. 輸入兩個整形數並

01.C語言程序設計--01.C語言基礎--01.C語言概述、02.GCC和GDB

.com c語言 c程序 設計 ont 圖片 發展 選項 第一個 走進嵌入式開發的世界,企業級項目課程讓你達到企業嵌入式應用開發要求。名師在線答疑,解決疑難。科學評測體系,系統評估學習。核心項目實........ 30 門課程 241小時12分鐘 824 人學習 學習

散分+快來報名“C語言指針與匯編內存地址”公開課

公開 lan shuf target dsd blank dmg userinfo gin iR歡2kaq崖居止40攘http://www.docin.com/app/user/userinfo?userid=179252984 Qsgb5V1仗mchttp://t.doc

Android-3Android的任務棧Task

集合 情況下 清除 bsp 生命周期方法 任務棧 保存 sin 也會 一、Android任務棧 概述:Android中的任務棧其實就是Activity的集合,在Android中退出程序的時候必須把任務棧中的所有Activity清除出棧,此時才能安全的完全的退出程序, 任務棧