2010-01-11 26 views
45

我很好奇C++中不同的常量聲明和定義選項的好處/壞處。時間最長的,我剛剛在頭文件的頂部聲明它們的類定義之前:在C++中聲明/定義類範圍常量的地方?

//.h 
const int MyConst = 10; 
const string MyStrConst = "String"; 
class MyClass { 
... 
}; 

雖然這污染了全局命名空間(我知道是一件壞事,但從來沒有發現一個原因爲什麼它不好的洗衣清單),常量仍將限定在單個翻譯單元中,因此不包含此標題的文件將無法訪問這些常量。但是,如果其他類定義了一個同名的常量,則可能會發生名稱衝突,這可能不是一件壞事,因爲它可能是一個可以重構的區域的良好指示。

最近,我決定,這將是更好的聲明類定義本身的內部類特定的常量:

//.h 
class MyClass { 
    public: 
     static const int MyConst = 10; 
... 
    private: 
     static const string MyStrConst; 
... 
}; 
//.cpp 
const string MyClass::MyStrConst = "String"; 

常量的可見性將取決於是否恆定,僅在內部所使用調整該類或其他使用該類的對象所需的類。這就是我現在想的最好的選擇,主要是因爲你可以保持內部類常量對類是私有的,而任何其他使用公共常量的類都會有更詳細的常量源(例如MyClass: :MYCONST)。它也不會污染全局命名空間。雖然它不利於在cpp文件中要求非整數初始化。

我也考慮將常量移入它們自己的頭文件中,並將它們包裝在名稱空間中,以防其他類需要常量,但不是整個類定義。

只是尋找意見和其他可能的選擇,我還沒有考慮。

回答

1

只要在頭文件中沒有引用它們,就可以在C++文件中聲明它們爲全局變量。然後他們對這個類是私有的,不會污染全局名稱空間。

+0

是的,但你必須使用'static'或在這種情況下,一個匿名的命名空間 - 如果你不這樣做,在一些實現你污染全局命名空間鏈接器使用並獲取鏈接名稱衝突... – hjhill 2010-01-11 17:30:25

9

全局名稱空間的污染很糟糕,因爲某人(例如,您使用的庫的作者)可能想要將名稱MyConst用於其他目的。這會導致嚴重的問題(不能一起使用的庫等)

如果常量鏈接到單個類,則第二種解決方案顯然是最好的。如果這不是那麼容易的話(想想物理或數學常量與程序中的類沒有關係),命名空間解決方案比這更好。順便說一句:如果您必須與舊的C++編譯器兼容,請記住其中的一些不能在頭文件中使用整型初始化 - 您必須在C++文件中初始化或在此情況下使用舊的enum技巧。

我認爲有常量沒有更好的選擇 - 至少不能認爲一個在目前的......

2

我個人使用的第二種方法;我已經使用了好幾年了,對我來說效果很好。

從一個可見性點,我會傾向於使私有常量文件級別的靜態,因爲執行文件之外的任何人都不需要知道它們存在;這有助於防止鏈式反應重新編譯,如果您需要更改其名稱或添加新名稱,因爲它們的名稱範圍與它們的使用範圍相同...

35

您聲明將非整數常量聲明爲靜態類成員「不利於在cpp文件中要求非整數初始化「並不完全可靠,可以這麼說。它確實需要在cpp文件中定義,但它不是「損害」,這是你的意圖的問題。在C++命名空間層次const對象具有默認的內部聯動,這意味着在你的原變種聲明

const string MyStrConst = "String"; 

相當於

static const string MyStrConst = "String"; 

也就是說,它會在每一個翻譯單元定義一個獨立MyStrConst對象該頭文件包含在其中。你知道嗎?這是你的意圖還是不是?

在任何情況下,如果你不特別需要在每一個翻譯單元一個單獨的對象,MyStrConst不斷的在你原來的例子聲明是不是一個好的做法。通常情況下,你只把一個非定義聲明在頭文件

extern const string MyStrConst; 

和cpp文件

const string MyStrConst = "String"; 

從而提供了一個定義,確保整個程序使用同一個常量對象。換句話說,當涉及到非整型常量時,通常的做法是在cpp文件中定義它們。所以,無論你如何聲明它(在課堂上或課堂外),你通常都必須處理必須在cpp文件中定義它的「不利因素」。當然,正如我上面所說的,使用名稱空間常量,您可以避免使用第一個變體中的內容,但這只是「延遲編碼」的一個示例。

無論如何,我認爲沒有理由過度複雜化該問題:如果該常量對類有明顯的「附件」,則應聲明爲類成員。

P.S.訪問說明符(public,protected,private)不控制的知名度的名稱。他們只控制其可訪問性。無論如何,這個名字仍然可見。

+0

請問可見性和可訪問性有什麼區別?我認爲他們是一樣的,你能舉個例子嗎? – toolchainX 2013-03-14 11:14:21

+0

@toolchainX:示例:成員函數可能是私有的,但函數對編譯器可能是「可見的」,因爲我們假定定義存在,編譯器可以「看見」它。編譯器只是強制不訪問[編譯器錯誤]。刪除定義或將定義放置在某處'隱藏'將使這些術語中的功能不可見 - 即使對於成員函數 - 也不管訪問[鏈接錯誤]。 – wardw 2013-05-30 21:58:28

+0

將它放在.cpp文件中是不利的,因爲編譯器不能內聯常量,因爲它不在編譯器的翻譯單元中。如果常量只是包裝一個整數的類,那麼最好將它放在頭文件中,以便編譯器知道它在所有編譯單元中的值。 – qbt937 2014-12-14 02:47:35

5

污染全局命名空間應該是明顯不好的。如果我包含一個頭文件,我不想遇到或調試與該頭中聲明的常量的名稱衝突。這些類型的錯誤真的令人沮喪,有時難以診斷。例如,我曾經反對在頭有這個規定,一個項目鏈接:

#define read _read 

如果常數的命名空間的污染,這是命名空間中的核廢料。這種表現是一系列非常奇怪的編譯器錯誤,抱怨錯過了_read函數,但只有在與該庫鏈接時纔會發生。我們最終將閱讀功能重新命名爲其他內容,這並不困難,但應該是不必要的。

您的第二個解決方案非常合理,因爲它將變量放入範圍。沒有理由這必須與類關聯,如果我需要在類之間共享常量,我會在自己的名稱空間和頭文件中聲明常量。這對於編譯時並不好,但有時候這是必要的。

我也看到有人將常量放入自己的類中,可以將其作爲單例實現。這對我來說似乎沒有獎勵,語言爲您提供了一些聲明常量的工具。

2

如果只有一個類將使用這些常量,請在類體內聲明它們爲static const。如果一堆相關的類將使用這些常量,則將它們聲明在只保存常量和實用程序方法的類/結構中,或者在專用命名空間中聲明。例如,

namespace MyAppAudioConstants 
{ 
    //declare constants here 
} 

如果它們是由整個應用程序(或其實質的塊)中使用的常量,聲明它們命名空間內的頭部即(隱式或顯式)包括無處不在。

namespace MyAppGlobalConstants 
{ 
    //declare constants here 
} 
1

不污染全局名稱空間,污染本地。

namespace Space 
    { 
    const int Pint; 
    class Class {}; 
    }; 

但實際上......

class Class 
    { 
    static int Bar() {return 357;} 
    };