2013-01-09 51 views
6

可能重複:
Difference between const declarations in C++const關鍵字位置

#include <iostream> 

class Bar{}; 

void foo(const Bar x){} //l5 
void foo(Bar x){}  //l6 
void foo(Bar const x){} //l7 

////pointer functions 

void foo(const Bar* x){} //l11 
void foo(Bar* x){}  //l12 
void foo(Bar* const x){} //l13 

編譯器輸出:(長話短說l5l6l7衝突;但只有l12l13衝突)

untitled.cpp:6:6: error: redefinition of ‘void foo(Bar)’ 
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here 
untitled.cpp:7:6: error: redefinition of ‘void foo(Bar)’ 
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here 
untitled.cpp:13:6: error: redefinition of ‘void foo(Bar*)’ 
untitled.cpp:12:6: error: ‘void foo(Bar*)’ previously defined here 

怎麼回事?

  1. 什麼是每一個聲明的含義
  2. 爲什麼所有3點聲明與對象功能的衝突,但只有2與指針的功能呢?
  3. 請詳細說明衝突是l12l13之間,即使l12不包含const關鍵字
  4. 真的對不起,如果瑣碎的問題

回答

5

「問題」是const參數值的參數不參與重載!

首先,Bar constconst Bar已經是相同的含義,所以它們會自動產生問題。但作爲函數參數,const不適用於重載,因此Bar版本的函數也看起來相同。參數表中的const僅告訴編譯器,您不打算在函數體中對其進行修改。

出於同樣的原因,Bar*Bar* const被視爲相同的:const適用於參數(沒有什麼指着)和不參與超載,所以你已經定義了相同的函數的值。

另一方面const Bar*意味着完全不同的東西:非const指針const對象(類型Bar)。由於類型不同,它會參與重載並允許該功能是唯一的。

1

不要緊,無論你把常量之前或種類名稱後。

15和17具有相同的參數參數列表。
這2個函數被認爲具有相同的原型並且是重複的。

功能#1

void foo(const int x) { 
return; 
} 

功能#2 - 重複參數參數列表

void foo(int const x) { 
return; 
} 

常量的位置是一樣的在你有實施例15和17。

要麼將​​根據維基百科的工作:

http://en.wikipedia.org/wiki/Const-correctness

+0

重寫第一句:在這個特定的上下文中,與編譯器無關。然而,一般來說,'const'會修改它之前的內容,並且在修改它之後(即'int const',而不是'const int')系統地放置'const'會使代碼更具可讀性。 –

0

原因前三產生衝突,是編譯器無法找出哪些功能在任何情況下使用。當您撥打foo(BarObject);時,編譯器可以很好地使用它們中的任何一個,無論是否將BarObject聲明爲const

但是與參數爲指針,當你調用foo(BarPointer);如果BarPointer被宣佈爲const Bar* BarPointer;,編譯器會挑]11,因爲它確保指向的對象不會在功能(不是這樣通過傳遞時,被修改的那些價值如前三)。如果它不是const,它不知道它是否應該調用]12]13,因爲Bar* const x的含義是,「x不能指向除作爲參數傳遞的內容之外的任何內容」,這與調用方無關。

小參考聲明:

const Bar x // x is an immutable copy of the original parameter. 
Bar const x // same as above and gets compiled, but cdecl says it is a syntax error. 

const Bar* x // x points to an object that can't be changed. 
Bar* const x // x can't point to any other object than the parameter passed. 
0

基本上,因爲調用函數時C++的值複製,沒有什麼可以從呼叫者角度的前三個區分。 (調用者知道函數不能改變它傳入的自己的值,所以從調用者的角度來看,每個函數參數在很多方面都是隱含不變的)。當你談論指針的時候,如果你將一個指針傳遞給一個常量而不是一個指向非常量的指針,那麼對於調用者(一個不會改變你的東西,另一個可能)會有所不同。這就是爲什麼l11和l12不衝突。

l12和l13衝突,因爲它們都是指向Bar *的指針(一個是const指針,一個不是,與l5-l7一樣的問題,與調用者沒有區別)。

最後這一點可能有點棘手 - 注意,雖然int const *a相同const int *a,這些一樣int * const a,前兩個是指向一個恆定的INT,另一種是恆定的指針一個int(即指針的值在以後不能改變)。

0
void foo(const Bar x){} 
void foo(Bar const x){} 

上述兩個是相同的,因爲這兩個說xBar類型的,並且它是const

void foo(Bar x){} 

與上述2這一個衝突,因爲x是否const與否是你的函數的一個實現細節,通過從功能簽名編譯器丟棄。因此,所有3個功能最終都具有相同的簽名void foo(Bar x)

void foo(Bar* x){} 
void foo(Bar* const x){} 

這與前面的情況類似;你表示指針xconst,即你不會將x重新指向你的函數中的其他東西。在兩種情況下,x指向的Bar對象爲非const。因此xconst是該函數的實現細節。

void foo(const Bar* x){} 

在這裏,我們表明x指向Bar對象,它是const。這與之前的兩例不同,所以沒有衝突。

0

對於前三個功能 - const對超載分辨率無關緊要,因爲通過轉移的情況變量。在堆棧中創建的參數副本,如果此副本從外部(調用方)角度更改或沒有更改,則無意義。它對函數本身很重要(內部)。

對於第二種情況,基於指針的函數,它是函數重載解析的重要組成部分,因爲副本不是在堆棧上創建的,而是從外部(調用者)角度來看,這意味着函數將會或不會修改參數的值。

對於最後兩個函數使用說一個編譯器:有x指針Bar,這Bar值由x指出我可能會改變。但在第一種情況下,您可以更改指針x本身的值(例如,指向另一個Bar)與第二種情況相反。而在這裏,我們處於第一種情況 - 指針的副本本身在堆棧中,如果它們在函數內部發生更改,則重載分辨率無效。