理解 《混沌 In C++::是類型?還是函數調用?》

原文及評論見: 《混沌 In C++::是類型?還是函數調用?》http://blog.csdn.net/Jinhao/archive/2004/06/29/29021.aspx

  看了原文的評論,發現有不少人誤解“函數聲明怎麼能當形參”。一開始,我也是一頭霧水,但後來總算是理解了,就在這裏稍微總結一下,也算是給自已提個醒吧。

  作者的代碼我在 VC++.NET2003編譯過。就目前來說,微軟正式發佈的C++編譯器中,VC++.NET2003是最貼近C++標準的。也正因爲如此,VC++.NET2003在編譯VC++.NET2002和VC++6的時候,千萬不要忽略其警告,因爲這些警告往往是在指出VC++.NET2003與以前版本的不同(甚至是不兼容)之處,如果簡單的忽略,代碼的行爲就可能不是你想要的。由於不是準備討論這個問題,所以只給一個常見的例子:

  bool bIsOk = nFlags & 0x02 == 0x02;
  
//warning C4554: “&” : 檢查運算符優先級可能存在的錯誤;使用圓括號闡明優先級

  在編譯時,你應該注意到這個“警告”(我認爲這是一個“錯誤”),並將代碼改爲:

  bool bIsOk = (nFlags & 0x02) == 0x02;

  • A a( A()) 到底是什麼?

  目前存在兩種說法:

    1. 函數聲明
    2. 變量聲明

  支持 “(2) 變量聲明” 這個觀點的人認爲,A()是調用“默認構造函數”構造一個A類型的臨時變量,然後再調用A的“拷貝構造函數”構造一個A類型的變量a。

  讓我們先看看下面的代碼表示什麼:

A a();

  這是變量聲明嗎?不是的,用默認構造函數聲明一個變量應該寫作:A a;;它應該是函數聲明:該函數名稱爲a,沒有參數,返回值爲A類型。

  我們再看看 A() 是什麼?實際上,在不同場合,A() 有不同的意義:

  1. 單獨使用: A();
    表示:struct A __cdecl(void),這是一個匿名的函數聲明。
  2. 函數聲明中:void func(A());
    表示:void __cdecl func(struct A (__cdecl*)(void)) ,很顯然,這裏A()就變成了一個函數指針聲明:struct A (__cdecl*)(void)。
  3. 在表達式中:?for_each(arr, arr+3, A());
    在這裏,A() 才能當作一個表達式,很顯然,唯有“默認構造函數”才能符合該用途。

  現在再來解決 A a( A()) 是什麼東西?在這裏,當同時可以解釋成函數聲明和變量聲明的場合,函數聲明優先。

  A a (A(), 3) ,就只能解釋成變量聲明(調用一般構造函數)。

  A a = A(),也只能解釋成變量聲明(調用拷貝構造函數)。

  • 這篇文章的意義在哪裏?

  有一部份人認爲這篇文章沒有意義,甚至無聊,更甚者認爲是在混淆視聽。理由是,寫程序者要有好的編碼風格,比如:

  1. A a (A()) 如果是變量聲明,就應該寫成: A a = A()。
  2. A a (A()) 如果是函數聲明,就應該寫成: A a(A (*) ())。

  這說法沒錯,而且好的風格極其重要。

  但是,許多人卻常常犯下類似的錯誤,並不是因爲編碼風格不好,而恰恰是對該文章要表達的內容不瞭解造成的。一個最常見的錯誤如下:

A a()

  本意可能是想聲明一個變量,結果卻變成函數聲明。就是因爲習慣性的加上了括號造成的。而如果沒有意識到這是一個函數聲明的話,可能就不太清楚到底錯在哪裏。

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