在 C++Builder 專案中,需要多個單元(.cpp)共享同一個全域變數(如目前登入使用者名稱)。直接在標頭檔定義會導致「重複定義」警告,且各單元實際上各自擁有一份副本,無法真正共享。
// Globals.h
#ifndef GlobalsH
#define GlobalsH
#include <Classes.hpp>
AnsiString UserName; // 危險!每個 include 此檔的 .cpp 都會產生一份獨立變數
#endif
結果:編譯器發出 N+1 次「重複定義」警告,賦值不跨單元生效。
Project.cpp)定義實體// Project.cpp
#include <vcl.h>
#pragma hdrstop
USEFORM("MainForm.cpp", MainForm);
// 全域變數實體定義(僅此處配置記憶體)
AnsiString UserName;
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try {
Application->Initialize();
Application->CreateForm(__classid(TMainForm), &MainForm);
Application->Run();
} catch (...) { /* ... */ }
return 0;
}
extern 宣告// Globals.h
#ifndef GlobalsH
#define GlobalsH
#include <Classes.hpp>
// 僅宣告,不配置記憶體
extern AnsiString UserName;
#endif
#include "Globals.h" 即可直接使用// Unit2.cpp
#include "Globals.h"
void SomeFunction() {
UserName = "Admin"; // 修改全域實體
ShowMessage(UserName); // 讀取全域實體
}
extern 告訴編譯器:此變數在別處定義,連結階段由連結器解析位址。若不想暴露全域變數,可封裝在命名空間或單例類別中:
// AppContext.h
namespace AppContext {
AnsiString& CurrentUser(); // 實作於 .cpp 內部靜態變數
}
優點:控制存取權、易於加入鎖定/日誌、單元測試可替換實作。
static AnsiString UserName; → 每個編譯單元各自一份,不是全域共享。AnsiString UserName; 且無 extern → 違反 ODR,連結錯誤或各自一份(視編譯器行為)。extern 宣告 → 連結錯誤「未定義符號」。