C++ Primer Plus的若干收穫--(十一),primerplus
本篇主要講了轉換函式的利與弊以及簡要介紹流與iostream檔案
由於在本篇仍然要使用上篇的Stonewt類,這裡首先給出其代碼
<span style="font-size:18px;">ifndef STONEWT_Husing std::cout;#define STONEWT_Hclass Stonewt{ public: Stonewt(double lbs,int stn); { stone=stn; pds_left=lbs; pounds=stn*Lbs_per_stn; } Stonewt(double lbs) { stone=int(lbs)/Lbs_per_stn;//integer divition pds_left=int(lbs)%Lbs_per_stn+lbs-int(lbs); pounds=lbs; } stonewt() {stone=pounds=pds_left=0;}; virtual ~Stonewt() {}; void show_lbs() const {cout<<pounds<<"pounds\n";}; void show_stn() const {cout<<stone<<"stone,"<<pds_left<<"pounds\n";}; private: enum{Lbs_per_stn=14}; int stone; double pds_left; double pounds;};#endif // STONEWT_H</span>
11.1 轉換函式
由上篇我們知道,由隱式轉換我們科以把一個double類型的值賦給Stonewt對象,但是,可以做相反的轉換嗎?也就是
<span style="font-size:18px;">Stonewt wolfe(285.7);double host=wolfe;//possible??</span>
要進行這種相反的轉換,必須使用特殊的C++運算子函數——轉換函式。轉換函式是使用者定義的強制類型轉換,可以像使用強制類型轉換那樣使用它們。如果定義了轉換函式,則可以進行下面的轉換
<span style="font-size:18px;">Stonewt wolfe(285.7);double host=double(wolfe);double star=(double)wolfe;</span>
11.2 建立轉換函式
要轉換typename類型,需要使用這種形式的轉換函式
<span style="font-size:18px;">operator typename();</span>
請注意一下幾點:
- 轉換函式必須是類方法;
- 轉換函式不能指定傳回型別;
- 轉換函式不能有參數。
這裡我們可以給出Stonewt的轉換函式
<span style="font-size:18px;">Stonewt::operator int() const{ return int(pounds+0.5);}Stonewt::operator double() const{ return pounds;}</span>
此後,我們寫這樣的語句將是合法的
<span style="font-size:18px;">Stonewt poppins;long gone=(double)poppins;long gone=int(poppins);</span>
11.3 轉換函式的缺點
和轉換建構函式一樣,轉換函式也有其缺點。提供自動執行、隱式轉換的函數所存在的問題是:在使用者不希望進行轉換時,轉換函式也可能進行轉換。為了避免這種情況我們可以用explicit。有了如下的聲明後,需可將運算子聲明為顯式的
<span style="font-size:18px;">explicit operator int() const;explicit opreator double() const;</span>
總之,C++為類提供了下面的類型轉換:
- 只有一個參數的類建構函式用於將類型與該參數形同的值轉換為類類型。比如,將int值賦給Stonewt對象時,接受int參數的Stonewt類建構函式將自動被調用。可以在構造聲明中用explicit防止隱式轉換。
- 被稱為轉換函式的特殊成員運算子函數,用於將類對象轉換為其他類型,轉換函式是類成員,沒有返回值、沒有參數、名為operator typename()。將類對象賦給typename變數或將其轉換為typename是,該函數將自動被調用。
學習了這麼多類的知識,一時難以消化,這裡不妨暫時轉入對檔案的輸入輸出中
11.4 流與緩衝區
C++把輸入和輸出看做位元組流。輸入時,程式從輸入資料流中抽取位元組;輸出時,程式將位元組插入到輸出資料流中。輸入資料流中的位元組可能來自鍵盤,也可能來自從初裝置或其他程式。同樣,輸出資料流中的位元組可以流向螢幕、印表機、存放裝置或其他裝置。流充當了程式和流源或流目標之間的橋樑。
輸入資料流需要兩個串連,每端各一個。檔案端部串連提供了流的來源,程式端串連將流的輸出部分轉儲到程式中。同樣,對輸出管理組件括將輸出資料流串連到程式以及將輸出目標與流關聯起來。通常,通過使用緩衝區可以更高效的處理輸入和輸出。緩衝區是用作中介的記憶體塊,它是將資訊從裝置傳輸到程式或從程式傳輸給裝置的臨時儲存工具。。通常,像磁碟儲存空間這種裝置已512位元組的塊為單位來傳輸資訊,而程式通常每次只能處理一個位元組的資訊。緩衝的方法則是從磁碟中讀取大量的資訊,將這些資訊儲存到緩衝區中,然後從緩衝區中每次讀取一個位元組。因為從記憶體中讀取資料比從磁碟中塊的多,因此這種方式更高效。
鍵盤每次提供一個字元,因此在這種情況下,程式無需緩衝區來協助匹配不同的資料轉送效率。然而,對鍵盤輸入進行緩衝可以讓使用者在將輸入傳輸給程式之前返回並更正。C++程式通常在使用者按下斷行符號時重新整理輸入緩衝區。這就是為什麼程式要到使用者按下斷行符號的時候在進行處理。對於螢幕輸出,C++程式通常在使用者發出分行符號是重新整理輸出緩衝區。
11.5 流、緩衝區與iostream檔案
管理流和緩衝區的工作有點複雜,iostream包含一些專門的設計來實現管理流和緩衝區的類。
- streambuf類為緩衝區提供了記憶體,並提供了用於填充緩衝區、訪問緩衝區內容、重新整理緩衝區和管理緩衝區記憶體的類方法;
- ios_base類表示流的一半特徵,如是否科讀取、是二進位還是文字資料流等;
- ios類基於ios_base類,其中包括了一個指向streambuf對象的指標成員;
- ostream類從ios類中派生而來,提供了輸出的方法;
- ostream類也是從ios類派生而來的,提供了輸入的方法;
- iostream類是基於istream和ostream類的,因此繼承了輸入方法和輸出方法。
這裡在稍微介紹下iostream類庫管理的一些細節:
- cin對象對應於標準輸入資料流。在預設情況下,這個流被關聯到標準的輸入裝置(鍵盤),wcin,wcout與此類似,但是處理的是wchar_t類型;
- cout對象與標準輸出資料流相對應。在預設的情況下,這個流被關聯在標準的輸出裝置(顯示器)中,wcout對象於此類似,但是處理的是wchar_t類型;
- cerr對象與標準錯誤流相對應。在預設情況下,這個流被關聯在標準輸出裝置(顯示器)。這個劉沒有被緩衝,這意味著資訊將被直接發送給螢幕,而不會等到緩衝區填滿或是新的分行符號。werr語氣類似。
- clog對象也對應於標準錯誤流。在預設情況下,這個流被關聯在標準輸出裝置(現實器),這個流被緩衝。wclog與此相類似。
- 對象代表流——這意味這什麼呢?當iostream檔案為程式聲明一個cout對象時,該對象將包括儲存了與輸出有關的資訊的資料成員,如現實資料時使用的欄位寬度、小數位元、計數方法以及用來處理緩衝區的streambuf對象的地址。下面的語句是通過是想streambuf對象將字串中的字元放入到cout管理的緩衝區中
<span style="font-size:18px;">cout<<"bju Masd";</span>
今天狀態不是太好(估計是因為今天要回學校,內心一直靜不下來),就寫這麼多了
看完c primer plus看什?
個人覺得看完了《c primer plus(第五版)》這本書,並且能看明白的話真不錯了,建議接下來看看《c專家編程》這本數,稍微難一點,再後面《c缺陷與陷阱》本書,稍微娛樂一些,有意思一些,《c primer plus(第五版)》《c和指標》《C Programming Language》個人覺得這三本書檔次差不多,選一本看看就可以了!
c primer plus 重新導向的問題
你沒有初始化 fname,所以fname 有可能沒有字串結束符 '\0'。
scanf 用在字串輸入的時候是很危險的。字串輸入最好用 fgets
在這裡你應該把 char fname[50]; 替換成 char fname[50]={0};
把 scanf("%s",fname); 替換成 fgets(fname,49,stdin);
這樣你就不需要在 fopen裡用"test.txt"了