天天看點

《C++程式設計慣用法——進階程式員常用方法和技巧》——2.3 公用資料

本節書摘來自異步社群出版社《c++程式設計慣用法——進階程式員常用方法和技巧》一書中的第2章,第2.3節,作者: 【美】robert b. murray ,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

假設有如下一個複數類:

這個類可能可以工作,但它的接口卻有着重大的缺陷。問題出在那兩個公用的資料成員:real和imag上面。這個接口保證complex對象中的實部和虛部會以浮點數的形式存儲在對象中。由于使用者代碼可以直接存取到公用的資料成員:

是以一旦我們需要改變資訊的存儲格式或存儲位置時,這樣的改動會變得相當困難。

假設在後面的某個版本中,我們希望将complex的實作(而不是接口)中的資訊存儲方式由笛卡兒坐标格式改為極坐标格式。(也許我們有着的某些算法在處理使用極坐标格式表示的數字時效果最好。)如果笛卡兒坐标是公用資料,我們就将陷入泥潭:我們将不得不改變所有的使用者代碼或者是在每個complex對象中同時維持極坐标和笛卡兒坐标格式。

如果我們在一開始就避免使用公用資料,我們就不會碰到這樣的問題了:

一旦接口中指定可以通過complex對象得到浮點型的實部和虛部之後,如何在對象中存儲這些浮點數就變成了類的私有實作細節。使用者代碼要想取得這些資料,就必須調用類的成員函數,而不是直接去通路資料成員。

現在對于使用者來說,唯一的不同就是他們為了擷取值将不得不多輸入兩個字元(即括号)。由于complex::real是一個内嵌函數,是以這兩種形式産生的代碼應該是一緻的——将取值操作封裝在一個内嵌函數中不會帶來任何效率上的損失。同樣,我們也可以将修改值的操作封裝到内嵌函數中去。

現在,我們的類中再也沒有公用資料了,為了将資訊以其他格式存儲而修改類的實作也變得容易起來:

此時,使用者代碼必須重新編譯,程式的性能也會有一定的影響,但程式的接口沒有改變。原來可以正常工作的程式仍然可以正常工作。

我們也可以将實作改為把資訊存儲到其他的位置上去:

我們将在第3章中解釋為什麼這麼做。

公用資料還會使得我們的類難以用來保證表示不變量。表示不變量是一個謂詞,對于某個完全被建構好的對象,它都将得到真值。

例如,假設我們有一個用來表示有理數的類rational,它裡面有兩個整型數(一個用于分子,一個用于分母):

如果我們的類具有這麼一個表示不變量(分母denom_d不可能為0),這将會使得我們的算法變得更簡單,并且更高效。我們在每個可能改變分母的函數中都對新的分母進行檢測,如果它是0的話,我們就向外報告一個錯誤[2]:

有了這兩個函數我們就可以保證不變量的成立,是以在rational的其他成員函數中,我們并不需要擔心出現分母為0的情況。如果我們将分母聲明為一個公用資料成員,我們就無法來保證不變量的成立,使用者代碼也就可以在任意時刻将分母指派為0。有關rational的所有操作也都将不得不對這種可能性進行檢測。

綜上所述,我們得到如下的結論:避免公用資料成員的出現。公用成員将使得我們很難去更改類的實作(如改變資訊的存儲格式或者存儲位置);它也無法保證表示不變量的長期有效性。

繼續閱讀