2010-09-09 49 views
1

我知道並理解全局變量和幻數是編程時要避免的事情,特別是隨着項目中代碼量的增加。然而,我想不出一個好的辦法來避免這兩者。如何避免全局變量和幻數?

說我有一個預先確定的變量代表屏幕寬度,並且該值需要在多個文件中。我可以做...

doSomethingWithValue(1920); 

但這是一個神奇的數字。但爲了避免這種情況,我會...

const int SCREEN_WIDTH = 1920; 

//In a later file... 
extern const int SCREEN_WIDTH; 
doSomethingWithValue(SCREEN_WIDTH); 

現在我正在使用全局變量。這裏有什麼解決方案?

+2

所以我聽說全局常量通常是正常的,它是導致真正問題的全局變量。多謝你們! – Lewis 2010-09-09 23:11:37

回答

11

在你的第二個例子,SCREEN_WIDTH是不是一個真正的變量 ,這是一個命名常量。根本不使用命名常量沒有任何問題。

在C語言中,如果因爲const對象不是常量而可能是整數常量,您可能需要使用枚舉。在C++中,像原始問題那樣使用const對象是首選,因爲在C++中,const對象是一個常量。

1.從技術上來說,是的,這是一個「變量」,但這個名稱並不真正「正確」,因爲它從不改變。

+0

所以全局變量很好,只要它們聲明爲const? – Lewis 2010-09-09 22:57:24

+1

像往常一樣,你不應該有金牌不變的規則,你應該知道最好的實踐背後的理由,以瞭解它們是否適用於你的案件。 – 2010-09-09 22:59:31

+0

@Lewis,指定的常量可以使用大括號「{}」進行適當限定。你的代碼片段並不能指出聲明的命名常量的位置。把它放在必要的最高範圍,但不要高。 – user122302 2010-09-09 23:00:47

1

全局變量的主要問題是當它們是非常量時。不變的全局變量幾乎不是這樣的問題,因爲您始終知道它們在任何地方使用的價值。

在這種情況下,一種理智的方法是創建一個常量名稱空間並將常量值放在那裏,以供程序中的任何位置參考。這很像你的第二個例子。

1

它們必須在某個地方定義。爲什麼不把定義放在.h文件或構建文件中?

2

爲什麼您需要首先硬編碼屏幕寬度?它從何而來? 在大多數實際應用中,它來自一些系統API,它告訴你當前正在運行哪個分辨率,或者系統能夠顯示哪些分辨率。

然後,您只需將該值傳遞給需要的任何地方。

總之,在這條線上:doSomethingWithValue(SCREEN_WIDTH);你已經在做它。 SCREEN_WIDTH在這個特定的例子中可能是全局的,但它不一定是,因爲函數不是作爲全局訪問它。你在運行時將值傳遞給函數,所以函數看到的不是全局變量,它只是一個普通的函數參數。

另一個重要的一點是,不可變的全球數據通常沒有問題。

全局常量通常很好。當您有可變全局狀態時,就會出現問題:可以在整個應用程序中訪問的對象,當時您可能會看到不同的值,具體取決於。這使得很難推理,並導致一些問題。

但全球常數是安全的。以pi爲例。這是一個數學常數,讓每個函數都看到pi是3.1415 .....沒有什麼壞處,因爲這就是它的,它不會改變。

如果屏幕寬度是一個硬編碼常量(如你的例子),那麼它也可以是一個全球性的,而不會造成嚴重破壞。 (儘管由於顯而易見的原因,它可能不應該在第一place9恆定

1

它不是一個變量,它是恆定的,這是在編譯時解決。

總之,如果你不喜歡這樣的一個「浮動」常量,你可以把它放在一個名稱空間或任何類型中,將所有這些類型的常量集中在一起,在某些情況下,你也可以考慮一個枚舉來組合相關的常量。針對您的情況,請避免使用固定的預定屏幕寬度,並使用正確的API在運行時檢索。

1

如果一個全局是必須的,那麼將其包裝在一個函數中並使用該函數來獲取該值通常是一個好主意。

另一篇文章可能help

+0

這是一個好主意嗎? – alternative 2010-09-09 23:12:07

+0

我的一個誤解問題。我指的是全局變量,問題是關於常量值。道歉。 – skimobear 2010-09-09 23:41:19

5

我會建議在頭文件中定義一個命名空間中的常數。那麼範圍不是全局的,你不需要在多個地方重新定義它(即使使用extern關鍵字)。

1

雖然在第二種情況下的全球是一個相當無害的,除非你設計這個東西,你當然屏幕寬度不會改變,我會用東西來獲得屏幕寬度動態地(例如,Windows上的GetSystemMetrics,或X上的XDisplayWidth)。

1

避免這種情況的一種方法是將您的程序設置爲對象並在對象上具有屬性(my_prog.screen_width)。要運行你的程序,讓main()實例化這個對象,並在對象上調用 - > go方法。

Java是否這樣做。很多。半體面的想法。

你的程序擴展獎金特點:

  • 當你使你的程序定製的某一天,你可以把它設置屬性在構造函數,而不是重新編譯所有。
  • 當您想要在同一個進程中彼此相鄰的兩個程序實例運行時,它們可以有不同的設置。

雖然這對快速一次性程序來說並不是什麼大事。

0

重要的是要認識到,即使是全局常量有時也會導致問題,如果它們將來需要更改。在某些情況下,你可能會認爲你根本不會讓他們改變,但其他時候事情可能並不那麼容易。例如,您的程序可能包含尺寸與屏幕匹配的圖形圖像;如果需要調整以在不同尺寸的屏幕上運行,會發生什麼情況?僅改變命名常量不一定會修復程序中嵌入的圖形圖像。如果它需要能夠在運行時決定使用什麼尺寸的屏幕呢?

不可能處理所有可能發生的意外情況,也不應該盡力保護那些根本不會發生的事情。儘管如此,人們應該注意事情會發生什麼變化,以避免把自己裝進一個角落。

設計一個類時,如果擁有一個返回不變值的虛擬只讀屬性,將允許該類的將來擴展返回不同的值。使用屬性而不是常數可能會有一些性能影響,但在某些情況下,靈活性將值得。如果有一種方法可以定義虛擬常量,我認爲沒有理由認爲它在理論上是不可能的.net允許它(包括虛表方法指針在表中包含常數值),但是到目前爲止我知道它沒有。