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

C++/CLI 核心機制:堆疊語意物件、追蹤參考與值型別語意

     編輯:關於C++

前言

C++/CLI 獨特地支援堆疊語意的參考型別實例與追蹤參考(tracking reference),填補了本地 C++ 物件模型與 CLI 記憶體管理的鴻溝。本文深入解析這兩大機制及其對拷貝建構、指派、相等性比較的影響。

堆疊語意參考型別實例

宣告語法如同值型別,但實際為參考型別:


Point p1;           // 預設建構
Point p2(3, 4);     // 引數建構

特性:

  • 受 CLI 執行階段管理,可能被 GC 移動
  • 不可為 static 或全域實例
  • sizeof(p1) 編譯錯誤(大小執行期才定),但 sizeof(Point^) 合法
  • 不可宣告堆疊語意的 CLI 陣列

追蹤參考 (Tracking Reference) %

對應本地 C++ 的 &,但能追蹤 GC 移動的物件:


Point^ hp = gcnew Point(2,5);
Point% p4 = *hp;              // 追蹤 hp 參考的物件
Point% p5 = *gcnew Point(2,5); // 追蹤臨時物件
  • % 僅限自動儲存期(區域變數)
  • 本地型別不能用 %,必須用 &
  • % 之於 ^,如同 & 之於 *
  • 綁定後不可重新綁定(如同 &)
  • 有追蹤參考的物件不會被 GC 回收

不可解參考的型別

System::String 和 array<T> 的控制代碼不能用 * 解參考。

取得控制代碼運算子 % (一元)

將堆疊語意實例轉為控制代碼:


Point p1;
Console::WriteLine("p1 is {0}", %p1);  // %p1 型別為 Point^ → 隱式轉 Object^
  • 無裝箱發生(參考型別直接轉型)
  • 不可用於本地型別
  • 產生 gc-lvalue:參考 GC 堆物件的運算式

GC-Lvalue 概念

C++/CLI 標準新增術語:gc-lvalue = 參考 CLI 堆中物件、或包含該物件資料成員的運算式。

  • *h (h 為 handle) → gc-lvalue
  • 追蹤參考 → gc-lvalue
  • %h → gc-lvalue
  • 標準 lvalue 可隱式轉換為 gc-lvalue

拷貝建構函數與指派運算子

參考型別不提供預設拷貝建構/指派(基類 Object 無此成員)。需手動實作:

拷貝建構函數


Point(Point% p) {  // 使用追蹤參考
    X = p.X;
    Y = p.Y;
}

對比本地 C++:Point(const Point& p)。參考型別無 const 語意。

指派運算子


Point% operator=(Point% p) {
    X = p.X;
    Y = p.Y;
    return *this;  // 回傳追蹤參考
}

相等性運算子


static bool operator==(Point% p1, Point% p2) {
    if (p1.GetType() == p2.GetType()) {
        return (p1.X == p2.X) && (p1.Y == p2.Y);
    }
    return false;
}
  • 追蹤參考永不為 nullptr,無需檢查
  • 使用 . 而非 -> 存取成員

雙重介面設計:C++/CLI vs 其他 .NET 語言

需求C++/CLI 開發者期望C#/VB.NET 開發者期望
物件複製拷貝建構、指派運算子Clone()、ICloneable
相等比較==/!= 運算子Equals()
參考語意堆疊語意、追蹤參考純控制代碼 (^)

建議策略

  • 必須實作 Equals(Object^) 覆寫(跨語言通用)
  • 為 C++/CLI 提供 operator==(T%, T%)(追蹤參考版)
  • 避免 提供 operator==(T^, T^)(語意模糊:比較參考還是值?)
  • System::String 例外:提供 ==(String^, String^) 比較值

其他實用主題

1. this 指標型別差異

  • 參考型別建構函數/成員函數:this 型別為 T^
  • 值型別建構函數/成員函數:this 型別為 interior_ptr<T>

2. const 在 CLI 型別中的處理

  • 參考型別成員函數不能標記 const/volatile
  • 建構函數中 this 型別為 R^(非 R* const)
  • 雖非 const,但控制代碼值不可修改

3. ToString 格式化


// 字串連接
return String::Concat("(", X, ",", Y, ")");

// 格式化(支援對齊、精度等)
return String::Format("({0},{1})", X, Y);

4. 編譯器偵測巨集


#if defined(__cplusplus_cli) && __cplusplus_cli == 200406L
// 支援 C++/CLI
#endif

5. System::Decimal 高精度金融計算


Decimal x = Decimal::Parse("23.00");   // scale=2
Decimal y = Decimal::Parse("2.000");   // scale=3
Decimal result = x * y + Decimal::Parse("2.5");  // scale=5
Console::WriteLine(result);  // 48.50000
  • 28 位數精度,無二進位浮點誤差
  • scale 屬性保留小數位數(含尾數 0)
  • 運算規則:加減取較大 scale,乘法 scale 相加,除法 scale 相減

6. 關鍵字衝突解決:__identifier


// 其他語言定義的類別有名為 delete 的 public 成員
ref class X { public: static void delete(); };

// C++/CLI 呼叫
X::__identifier(delete)();  // 避開 C++ delete 關鍵字

7. literal 編譯期常數


literal double PI = 3.1415926;
literal int MinValue = -10, MaxValue = 10;
literal int Range = MaxValue - MinValue + 1;  // 編譯期計算
literal String^ Title = "Annual Report";      // 唯一允許的控制代碼常值
  • 類似 static const 但不可標記 static
  • 編譯器直接置換為常值
  • 支援標量型別、enum、字串常值、nullptr

總結

堆疊語意實例與追蹤參考是 C++/CLI 連結本地 C++ 習慣與 CLI 記憶體模型的關鍵橋樑。正確實作拷貝/指派/相等性、理解 this 型別差異、提供雙重介面(Equals + operator==)、善用 Decimal/literal/__identifier,能撰寫高效能、跨語言互操作性佳的 CLI 程式庫。

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