關於 C++中 while(cin &gt&gt a) 的解釋 和 operator void*() 和 bool operator!()的理解

做題的時候,我經常用while(cin>>a)這樣的模式來  實現 連續輸入 或 統計輸入連續數字的個數 等功能,但是一直都對其中的原理感到迷迷糊糊,我覺得只會用怎麼行,還得搞明白 其所以然 來。所以看了一些資料和大佬們的博客,然後寫這樣一篇博客來解釋其中的原理。


 

使用情形 以及 跳出的while(cin>>a)的方法

while(cin>>a)的意思是 只要輸入的值有效,那麼就執行while體內的語句。while循環結束 (跳出流對象)的時候 ,通過檢測其流的狀態來判斷結束:
(1)若流是有效的,即流未遇到錯誤,那麼檢測成功。
(2)若遇到一個無效的輸入時(例如:上述的a是int類型的,但輸入的值不是一個整數),istream對象的狀態會變爲無效,條件就爲假。
(3)若遇到文件結束符也可以跳出while(cin>>a)。在windows系統中,輸入文件結束符的方法是先按Ctrl+Z,然後再按Enter。在UNIX系統中,包括Mac OS X系統中,文件結束輸入爲Ctrl+D。
  特別的:在while循環中以EOF作爲文件結束標誌(end of file),EOF是針對文件輸入的情況,文件指針如果指向文件尾就會等於EOF。 這種以EOF作爲文件結束標誌的文件,必須是文本文件!在文本文件中,數據都是以字符ASCII代碼值的形式存放。我們知道,ASCII代碼值的範圍是0~127,不可能出現-1,因此可以用EOF作爲文件結束標誌。
   




原理剖析

跳不跳出while(cin>>a)循環 關鍵在於 cin>>a 的值 是不是 假(0)。

運算符返回的是流對象的引用,cin是一個流對象,而>>運算符返回左邊的流對象,也就是說cin>>val返回cin,於是while(cin>>val)就變成了while(cin),問題就變成了一個流對象在判斷語句中的合法性。 (注意一下:右移運算符>>的結合方向是從左到右 輸入流類(istream) 把 >> 重載了)

如果定義了一個類(沒有重載  void * 和 ! 運算符的類),然後定義該類的對象,然後使用 while 或者 if 語句來判斷它是不合法的。可是爲什麼while(cin) 和 if(cin)都是合法的呢?原來 輸入流類(istream) 重載了 void*  ! 這兩個運算符!!

打開iostream.h文件,可以看到 operator void *() const和bool operator!() const 這兩個函數。這兩個函數使得流對象可作爲判斷語句的內容。

可是重載這兩個運算符 跟可作爲判斷語句的內容有什麼關係?

原因是這樣的:
(以下用if來解釋,其實while和if 在處理這方面的情況是一樣的)
①先來測試下沒有重載上述運算符的情況

#include <iostream>
using namespace std;
class A
{
	
};

int main()
{
    A a;
    if(a)
        cout<<"YES";
    
    return 0;
}

不出所料,報錯信息如下:

[Error] could not convert 'a' from 'A' to 'bool'

分析:說明編譯器編譯的時候 不能 將對象a轉換爲bool類型,不能轉換的話 也就無法判斷if裏判斷語句的內容是 真(非0) 是 假(0) 了。


①改進:重載了void*後

#include <iostream>
using namespace std;
class A
{
public:
	//返回值類型 就是void* 不用額外寫 
    operator void*() 
    {
        return (void*)0;
    }
};

int main()
{
    A a;
    if(a)
        cout<<"YES";
    
    return 0;
}

分析:這樣寫後,編譯就沒問題了。
因爲在a不能直接轉換爲bool類型的情況下,會試圖先進行 (void*)a 這樣的操作,這個操作會直接調用A類的成員函數operator void*(),這個函數返回一個void*的數據,所以這裏的if(a)其實就是if((void*)a),然後根據強制轉換後的結果來進行if的判斷,這裏顯然應該不輸出。如果改成return (void*)this,那麼就可以看到運行後輸出了YES


②然後來看看下面的代碼

#include <iostream>
using namespace std;
class A
{
public:
	//返回值類型 就是void* 不用額外寫 
    operator void*() 
    {
        cout<<"a";
        return (void*)0;
    }
};

int main()
{
    A a;
    if(!a)
        cout<<"YES";
    
    return 0;
}

輸出:aYes

分析:當程序執行到if(!a)時,對於!a,同樣是由於a無法直接轉化爲bool類型,所以!a就等同於!((void*)a),由於(void*)a的值爲0 (調用了A類的成員函數operator void*(),然後返回了(void*)0 ),所以!a爲真,那麼就可以執行if(!a)裏面的語句了。


②改進:重載了 ! 運算符

#include <iostream>
using namespace std;
class A
{
public:
	//返回值類型 就是void* 不用額外寫 
    operator void*() 
    {
        cout<<"a";
        return (void*)0;
    }
    
    bool operator!()
    {
    	cout<<"A";
    	return true;
    }
};

int main()
{
    A a;
    if(!a)
        cout<<"YES";
    
    return 0;
}

輸出:AYes

分析:重載了運算符!後, !a就直接執行了operator!()函數,該函數返回true,所以可以執行if(!a)裏面的語句。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章