C++ 無原生 property 語法,慣例以 get_X()/set_X() 模擬,但手寫極其繁瑣。利用巨集的 token-pasting(##)與字串化(#)特性,可自動產生屬性存取器,大幅簡化類別宣告。
#define AUTO_PROPERTY(type, name) \
private: type m_##name; \
public: type get_##name() const { return m_##name; } \
public: void set_##name(const type& value) { m_##name = value; }
// 使用
class MyClass {
AUTO_PROPERTY(int, data) // 自動展開為 m_data + get_data() + set_data()
};
展開後等同:
class MyClass {
private: int m_data;
public: int get_data() const { return m_data; }
public: void set_data(const int& value) { m_data = value; }
};
// 僅宣告(置於類別內)
#define PROPERTY(type, name) \
private: type m_##name; \
public: type get_##name() const; \
public: void set_##name(const type& value);
// Getter 實作(置於 .cpp)
#define PROPERTY_GET(classname, type, name) \
type classname::get_##name() const
// Setter 實作
#define PROPERTY_SET(classname, type, name) \
void classname::set_##name(const type& value)
// 使用範例
class MyClass {
public:
PROPERTY(int, data)
};
PROPERTY_GET(MyClass, int, data) {
return m_data; // 可加入邏輯、日誌、驗證
}
PROPERTY_SET(MyClass, int, data) {
if (value >= 0) m_data = value; // 自定義驗證
}
巨集缺點:除錯困難、無型別安全、IDE 智慧提示失效。現代專案建議:
struct Config { int port; std::string host; }; 直接存取,配合 std::optional 表達可選性。operator T() / operator=(T) 封裝邏輯,語法如 obj.prop = 5; int x = obj.prop;。Boost.PFR、magic_get 實現編譯期屬性遍歷。std::property 仍在提案階段。| 專案類型 | 建議做法 |
|---|---|
| 舊式 MFC/ATL 維護專案 | 巨集可接受,降低改寫風險 |
| 新專案(C++17+) | 優先公開成員或 Proxy 類別 |
| 需序列化/OR Mapping | 配合反射庫(Boost.PFR) |
| 需細粒度存取控制 | 手寫 Getter/Setter 或 Proxy |
巨集能以極低成本消除重複程式碼,適合維護期專案快速遷移。
新專務請擁抱現代 C++ 語法與庫,讓編譯器與 IDE 成為你的盟友,而非巨集的受害者。