C++巨集程式設計技巧
阿新 • • 發佈:2018-12-13
下面的程式碼並非按照規範格式來寫,僅作示範用途。
常用符號
- ##
連線符,可將多個識別符號拼接起來,組成一個完整的識別符號。
//定義巨集,用來列印整型變數
#define PRINT(x) printf("%d\n", a##x)
int a1 = 1;
int a2 = 2;
PRINT(1); //等同於printf("%d\n", a1),輸出1
PRINT(2); //等同於printf("%d\n", a2),輸出2
- #
新增雙引號,轉成字串。
//定義巨集,轉成字串 #define STR(x) #x //等同於printf("%s\n", "Hello, world!"); printf("%s\n", STR(Hello, world!));
- #@
新增單引號,轉成字元。
//定義巨集,將x轉成字元
#define CH(x) #@x
char a = CH(M); //等同於char a = 'M'
printf("%c\n", a);
除了這些基本符號以外,還有一些巧妙使用技巧。
可以利用巨集來完成註冊類功能的實現。
高階技巧
- 註冊類
在微軟的MFC框架中,時常可以見到視窗註冊類的身影。
通過API將使用者自定義的類註冊一下,便可以使用它們執行某些特定的功能。
這裡我要介紹的是,自定義註冊方法和呼叫類的方法,將使用者自定義類註冊成功後就可以通過類名來獲取該類的物件,這在沒有反射機制的C++中是十分有用的功能。
- 使用者可以用map容器儲存['A', func]鍵值對,實現類與特定函式一一對應關係。
- 規定註冊類的許可權,只有註冊後才能執行某些操作。
- 將類名字串儲存在陣列中,使用for迴圈語句或if...else條件語句動態建立所需的類。
下面對註冊類的一種簡單使用進行舉例:
//定義用來生成類、註冊類的巨集 //組合類名 #define CLS(x) My##x //建立註冊類 #define CREATE_CLS(x) \ class CLS(x) : public RegCls \ { \ public: \ CLS(x) *Instance() \ { \ static CLS(x) *pInstance = new CLS(x); \ if (pInstance == nullptr) \ { \ pInstance = new CLS(x); \ } \ return pInstance; \ } \ } //使用類名進行類註冊,#x用來將類名轉成字串 #define REG(x) \ CREATE_CLS(x) \ g_ClsMap[#x] = CLS(x)::Instance
其中g_ClsMap是全域性變數,需要自定義。
“\”符號用來連線多行程式碼,表明它們屬於同一個巨集定義。
CLS(x)用來組合連線類名,生成識別符號My##x,如CLS(Dog)會產生識別符號MyDog。
下面定義方法來呼叫註冊類:
//定義型別func,返回RegCls *型別,無參函式
typedef std::function<RegCls *()> func;
//定義全域性map變數,儲存類名字串和獲取單例的函式指標
std::map<string, func> g_ClsMap;
//註冊兩個類,類名分別為MyDog和MyCat
REG(Dog);
REG(Cat);
//使用"Dog"和"Cat"字串獲取類的單例物件
RegCls *pDog = g_ClsMap["Dog"]();
RegCls *pCat = g_ClsMap["Cat"]();
本人在使用巨集的過程中,還總結了一個可簡化程式碼的巨集使用技巧。
相信在程式設計過程中,經常會遇到相似程式碼重複多次出現的情況,顯然巨集就是為這種重複工作而生的東東。
舉例如下:
//fd為檔案描述符,以只讀模式開啟a.txt檔案
int fd = open("a.txt", O_RDONLY);
if (fd < 0)
{
cout << "open failed\n";
return -1;
}
//讀取fd所指的檔案內容,並儲存在buf中
int res = read(fd, buf, sizeof(buf));
if (res < 0)
{
cout << "read failed\n";
return -1;
}
上面是Linux系統中常見的開啟檔案並讀取檔案內容的操作,可發現判斷返回結果的程式碼都是類似的,很容易聯想到使用巨集進行簡化。其實巨集定義的位置也有講究,不僅可在檔案頭部定義,也可以在函式內部定義。無論在函式內部還是外部定義巨集,都可以在之後使用該巨集,作用域均為全域性範圍。
通過#define和#undef組合,可以將巨集作用域限制在標籤之間。
使用巨集簡化程式碼如下:
//定義巨集,檢查變數值
#define CHECK(x, str) \
if (x < 0) \
{ \
cout << str << " failed\n"; \
return -1; \
}
int fd = open("a.txt", O_RDONLY);
CHECK(fd, "open");
int res = read(fd, buf, sizeof(buf));
CHECK(res, "read");
//取消巨集定義
#undef CHECK
這段程式碼可以放到函式內部,用時定義,用完即銷。
本次關於巨集的介紹就到此為止,如有不對之處,請多多指教!