2009-02-24 69 views
3

我有一些代碼在C++中有一個動態類系統,它有一個名爲GetClassName()的成員,這是一個相當無害的名字。但是,當被包含在一個Windows頭文件的大型項目中時,所有的問題都會發生。顯然,Windows使用了一個#define GetClassName(GetClassNameA或GetClassNameW),它把所有東西都搞砸了,而且我的虛擬調用樹全部搞砸了,這讓我在昏暗的愚蠢編譯器調試中失去了一天,試圖弄清楚什麼是錯誤的。Windows API和GetClassName()?別的名字?

因此,除了我詛咒微軟使用如此可怕的衝突名稱來定義#define(我的意思是有人應該誠實地爲此拍攝!),我要求3個目的。

  1. 什麼是 GetClassName()的另一個好名字?
  2. 反正是有 解決這個問題,所以在未來,其他 開發我的代碼庫不會 遭受同樣的命運
  3. 而對於 後人當別人 遇到這種類似的 莫名其妙的錯誤
+0

更糟糕的是,在函數名稱周圍放置括號以避免宏替換的舊C語言(例如, 「const char *(GetClassName)()」)在這裏不起作用。我想這是因爲WinUser.h包含「#define GetClassName GetClassNameW」而不是「#define GetClassName(a,b,c)GetClassNameW(a,b,c)」。 – bk1e 2009-02-24 06:55:06

+0

是的,這是純粹的邪惡C :) – 2009-02-24 09:13:38

回答

2

我會重命名該方法。

當然,人們可以說

#include <windows.h> 
#undef GetClassName 

,但它不乾淨,一個代碼的用戶應該還記得,當他們調用Win32函數寫:: GetClassNameW。

可以在他的類中提供GetClassNameA和GetClassNameW方法,但它很難看。

我看到了兩個辦法:要麼延長或縮短名字:)

1)添加前綴爲子系統的所有功能,FE TI_(類型信息):

TI_GetClassName() 
TI_GetBaseClass() 
TI_IsDerivedFromClass() 
etc 

2)或把它們放進一些ICLASS接口

interface IClass { 
GetName(); 
GetBase(); 
IsDerivedFrom(); 
etc 

和從單一方法返回該接口,
使得GetClassName()變爲

GetClass()->GetName() 
5
  1. ClassGetName()
  2. #undef GetClassName
  3. WinAPI是一個C API。沒有名稱空間。其他一些平臺試圖通過爲所有符號名加前綴來緩解這一點,但最終也會分崩離析。最好的選擇是:如果你編寫的代碼不依賴於Windows Platform SDK頭文件,那麼然後不要#include他們
+0

我的代碼不依賴於任何Windows頭文件,並且它自己傳遞了單元測試,但是當客戶代碼使用它們時,BAM發生錯誤。在我追蹤Windows頭文件問題之前,對我來說這是一個完全神祕的東西:( – 2009-02-24 02:56:45

+0

也許他們使用的是包含PSDK頭文件的預編譯頭文件?一個好主意,當您構建使用這些頭文件的大量代碼時,因爲它可以大大加快構建時間......但值得禁用的文件不需要 – Shog9 2009-02-24 03:07:17

2

GetWindowClassName也許?事實上,GetClassName對於這個API來說並不是一個糟糕的名字,因爲它涉及到窗口類。真正的問題是它是一個C API聲明,C聲明沒有辦法引入一個不會污染全局名稱空間的可重用聲明。

這比C++語言的失敗要多得多。

2

Windows API充斥着大量乾淨的名稱,這些名稱可根據生成選項擴展爲具有指示ASCII/UTF-16後綴的函數名稱。如果它們以「W32」或類似的(OS X上的一個「NS」)作爲前綴,它會很好,但他們選擇不保證API「乾淨」。

由於它是一個更容易改變你的代碼比他們的API,這裏有幾個建議:

1)瞭解Windows的API(它實際上不是那麼大),或至少熟悉MSDN如此!當遇到難以解釋的程序流程時,您可以查找名稱衝突。

2)在代碼中使用明確的作用域解析(MyClass :: GetClassName())。不幸的是,這會打破虛擬功能調度,所以要小心這個。

3)在代碼中使用不同的命名約定。 MS總是使用CamelCase,因此如果您選擇其他約定(get_class_name(),getClassName()等),則不會發生衝突。4)我個人很討厭命名我的獲得者「GetX()」和「SetX()」,但更喜歡依賴重載機制,並使用「xtype X()const」作爲獲取者和「void X (xtype newval)「。你的里程可能會有所不同,但我覺得它更清潔& get/set是顯而易見的論據。顯然,如果你使用默認參數,你必須小心。

祝你好運!