[139] JUCE Diary #13:C++ namespace 的必要

[139] JUCE Diary #13:C++ namespace 的必要

前言

C++ namespace 的用意是減少名稱衝突,Objective-C 則是以「加上前贅詞」(「贅」者,多餘、沒有用處。)的方式處理,老實說有點不牢靠。

JUCE 的公開類別置放於 juce:: 命名空間裡。不過,預設情況下由於
JuceHeader.h 引入了 using namespace juce;,因此使用 JUCE 類別不需要加上 juce::。這麼做純粹是為了節省打字時間,並試圖讓「版面」更乾淨,但不應視為「最佳實務」。這個預設行為可以透過定義 DONT_SET_USING_JUCE_NAMESPACE=1 來改變。不過,經驗顯示加上後反而是自找麻煩...

那些年,我們一起經歷的不美好...

C++ namespace 的美意如前述,但現實是殘酷的,「人多必有枯枝,碼厚總有遺毒」。軟體專案發展到一定規模,複雜度日益升高,「同樣功能的模組重複實作」的問題無法避免。以 C++ 類別為例,當專案用到兩個不同的函式庫時,很可能會寫出名稱一模一樣,但介面與實作不盡相同的類別。然後麻煩就來了...

JUCE 裡有一個 juce::Rectangle 類別跟 Windows SDK 裡的 Rectangle 函數衝突,問題發生在引入 Windows.h 後,會出現以下錯誤:

error C2872: 'Rectangle' : ambiguous symbol 1> could be 'C:\Programme\Microsoft SDKs\Windows\v7.0A\include\wingdi.h(3989) : BOOL Rectangle(HDC,int,int,int,int)

Win32 API 多為 C 語言介面,無「命名空間」概念,亦無使用「前贅詞」保護,先寫先贏。再加上幾乎是開發 Windows 應用程式必備,影響深遠。前面提到,JUCE 預設會把 juce:: 命名空間捨去,然後就打架了。

針對 Rectangle 的衝突問題,解法至少二個:

簡單的作法是連同命名空間一起寫,像這樣: juce::Rectangle,搞定。由此可看出 namespace 確實有其效用,若是 JUCE Rectangle 沒宣告在 juce:: 命名空間,那麼這個簡單作法便不可行。

另一種作法是在引入 Windows.h 前定義 NOGDI,不要引入 Rectangle 函數,如下:

#define NOGDI
#include <windows.h>
#include <WinBase.h>
#include <atomic>

C++ namespace 立意良善,但使用上相對麻煩,有些人就怕麻煩(麻煩可能比蟑螂還可怕),不重視、不使用命名空間,原本獨立發展的專案沒有問題,一旦產生交集,遇到的問題可能不是三兩下解決得了。

敝社的 C++ 程式碼慣例是自定義的類別一律放在公司命名空間內,視個別專案再放到獨自的命名空間裡。這麼做,對大家都好。

還是嫌麻煩的話,拜託,請謹守底線——不要在標頭檔(.h/.hpp)使用 using namespace std

嚴以律己

Google C++ Style Guide 對於命名空間的規範相對嚴格,不準用 using namespace xxx。與其不知何時被反咬,倒不如一開始就嚴格要求,將發生衝突的機率降至最低。

Cover Image: http://static.zoommyapp.com/full/77057.jpg