首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++Builder __property 擴展詳解:自定義屬性完整指南(含陣列屬性、異常安全與 IDE 整合)

     編輯:關於C++

C++Builder __property 擴展詳解:自定義屬性完整指南

Borland C++ Builder 引入 __property 關鍵字,將 Delphi 風格的「屬性」語法帶入 C++,讓類成員訪問兼具字段般簡潔與方法般封裝的雙重優勢。本文系統講解簡單屬性、陣列屬性、唯讀屬性、預設屬性、存取指定符,並針對商業級開發提出異常安全與IDE 整合最佳實踐。

語法速覽

__property <類型> <名稱> [<索引列表>]
    = { read=<讀取器>, write=<寫入器>, stored=<布爾/方法>, default=<值>, nodefault, index=<整數> };
  • read / write:必填至少一個,對應成員函數或字段。
  • stored:決定是否序列化至 .dfm,預設 true。
  • default / nodefault:指定預設值,IDE 物件檢查器以此決定是否顯示粗體。
  • index:多屬性共用同一讀寫器時的區分標識。

範例 1:簡單標量屬性

class TSome {
protected:
    int a, b, s;
    int GetSum() { return s = a + b; }      // 讀取器
    void SetSum(int val) { s = val; }       // 寫入器
public:
    __property int Sum = { read=GetSum, write=SetSum, nodefault };
};

使用:obj.Sum = 10; → 呼叫 SetSum(10);int v = obj.Sum; → 呼叫 GetSum()。

範例 2:陣列屬性(索引器)

class TSome {
private:
    TList *list;
protected:
    void* GetItem(int i) {
        return (i >= 0 && i < list->Count) ? list->Items[i] : nullptr;
    }
    void SetItem(int i, void* ptr) {
        if (i >= 0 && i < list->Count) list->Items[i] = ptr;
        else if (i == list->Count) list->Add(ptr);  // 允許尾部擴充
    }
    int GetCount() { return list->Count; }
public:
    TSome() : list(new TList) {}
    ~TSome() { delete list; }

    __property void* Items[int i] = { read=GetItem, write=SetItem };
    __property int Count = { read=GetCount, nodefault };  // 唯讀
};

使用:obj.Items[3] = ptr; → SetItem(3, ptr);int n = obj.Count; → GetCount()。

進階模式

模式語法示例用途
預設屬性__property void* Items[int i] = { ... }; // 類外可 obj[i]類似 std::vector::operator[]
索引屬性共用器__property int Prop1 = { read=GetVal, write=SetVal, index=1 };
__property int Prop2 = { read=GetVal, write=SetVal, index=2 };
單一方法處理多屬性
存取控制__property int X = { read=GetX, write=SetX, protected };限制繼承類可見性
屬性別名__property int Alias = { read=GetReal, write=SetReal, index=0 };向後相容重命名

商業級開發必讀:異常安全與 IDE 整合

  1. 讀寫器必須異常中性
    屬性讀寫可能發生於 Object Inspector、DFM 流式讀寫、Assign() 複製等任意時機。
    ✅ 正確:
    void SetName(const AnsiString& s) {
        if (s.IsEmpty()) throw EArgumentException("Name cannot be empty");
        FName = s;  // AnsiString 賦值不拋異常
    }
    ❌ 錯誤:在寫入器中直接拋出未捕獲的異常導致 IDE 崩潰或 DFM 載入失敗。
  2. 實作 stored 動態判斷
    bool __fastcall IsNameStored() { return FName != DefaultName; }
    __property AnsiString Name = { read=GetName, write=SetName, stored=IsNameStored };
    避免將預設值寫入 DFM,減小表單檔案體積。
  3. 預設值與 nodefault 選擇
    整數/枚舉/集合類型建議顯式 default=0;字串/物件/浮點數務必用 nodefault,避免浮點比較陷阱。
  4. 屬性編輯器註冊
    複雜類型(顏色、字體、集合、圖片)需編寫 TPropertyEditor 子類並 RegisterPropertyEditor(),否則 Object Inspector 僅顯示原始值。

編譯器支援邊界

  • ✅ Clang-enhanced 編譯器(10.4+)完整支援。
  • ✅ 傳統編譯器(舊版)支援,但模板類中定義屬性可能觸發內部錯誤。
  • ❌ 標準 C++(GCC/Clang/MSVC)不支援__property,跨平台代碼請改用 getter/setter 命名慣例 + 宏條件編譯隔離。

善用 __property,你的 VCL 元件將擁有原生級的設計時體驗;配合異常安全守則,更能讓商業級元件在 IDE 中穩如磐石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved