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

C++/CLI 值型別完整解析:定義、語意差異、基本型別對應與複數實作範例

     編輯:關於C++

前言

值型別(value class/struct)是輕量級的 CLI 型別機制,適合小型資料結構,語意接近基本數值型別。不受 GC 管理、無繼承、預設逐位複製,效能優於參考型別。本文系統解析定義語法、與參考型別差異、基本型別對應表、複數類別實作範例。

值型別定義與基本特性


using namespace System;

public value class Point {
    int x, y;
public:
    property int X { int get() { return x; } void set(int v) { x = v; } }
    property int Y { int get() { return y; } void set(int v) { y = v; } }
    
    Point(int xor, int yor) { X = xor; Y = yor; }
    void Move(int xor, int yor) { X = xor; Y = yor; }
    
    virtual bool Equals(Object^ obj) override { /* ... */ }
    static bool operator==(Point p1, Point p2) { 
        return (p1.X == p2.X) && (p1.Y == p2.Y); 
    }
    virtual int GetHashCode() override { return X ^ (Y << 1); }
    virtual String^ ToString() override { return String::Concat("(", X, ",", Y, ")"); }
};

關鍵特性總結

特性值型別參考型別
關鍵字value class/structref class/struct
基底類別System::ValueType (隱式 sealed)System::Object
記憶體管理堆疊/內嵌,非 GCGC 堆
繼承不可繼承 (sealed)可繼承
預設建構函數隱式(全零初始化),不可自訂可自訂
拷貝/指派隱式逐位複製,不可多載無預設,需手動實作
靜態實例允許禁止
this 型別interior_ptr<T>T^

無預設建構函數的含義

  • CLI 保證:值型別實例建立時,所有位元歸零
  • int→0, bool→false, handle→nullptr
  • 若「全零」非合法狀態(如檔案控制代碼、非零 ID),必須改用參考型別

Equals 實作簡化

值型別傳遞給 Equals(Object^) 時發生裝箱,建立新物件副本:


virtual bool Equals(Object^ obj) override {
    if (obj == nullptr) return false;
    if (GetType() == obj->GetType()) {
        Point^ p = static_cast(obj);  // 拆箱
        return (X == p->X) && (Y == p->Y);
    }
    return false;
}
  • 無需檢查「同一實例」(值型別無別名問題)
  • 無需檢查型別相容性(sealed 型別)

== 運算子多載選擇


// 1. 以值傳遞(推薦:簡潔、無歧義)
static bool operator==(Point p1, Point p2) { ... }

// 2. 追蹤參考版(功能相同,較冗長)
static bool operator==(Point% p1, Point% p2) { ... }

// 3. 本地參考版(相容本地 C++ 語法)
static bool operator==(Point& p1, Point& p2) { ... }

建議:只保留一個版本避免多載解析歧義。以值傳遞版最符合值型別語意。

基本型別對應表 (Microsoft 實作)

C++/CLI 型別CLI 值型別
boolSystem::Boolean
wchar_tSystem::Char
signed charSystem::SByte
unsigned charSystem::Byte
charSystem::SByte 或 System::Byte
shortSystem::Int16
unsigned shortSystem::UInt16
intSystem::Int32
unsigned intSystem::UInt32
long longSystem::Int64
unsigned long longSystem::UInt64
floatSystem::Single
doubleSystem::Double

補充:System::Decimal 無對應 C++/CLI 基本型別,需用 Decimal::Parse。

基本型別成員存取範例


Int32::MaxValue                    // 2147483647
Double::Parse("123.45e-1")         // 12.345
10.2f.ToString()                   // "10.2" (float→Single)
(10 + 5.9).ToString()              // "15.9" (double→Double)
(100).ToString()                   // 語法錯誤:100. 被視為 double 常數
100 .ToString()                    // "100" (空格隔開避免歧義)

複數值型別完整實作


using namespace System;

public value class Complex {
    double real, imag;
public:
    // 唯讀靜態常數 i = sqrt(-1)
    static initonly Complex i;
    static Complex() { i = Complex(0.0, 1.0); }
    
    Complex(double r) : real(r), imag(0.0) {}
    Complex(double r, double i) : real(r), imag(i) {}
    
    property double Real { double get() { return real; } void set(double v) { real = v; } }
    property double Imag { double get() { return imag; } void set(double v) { imag = v; } }
    
    static Complex operator+(Complex z1, Complex z2) {
        return Complex(z1.real + z2.real, z1.imag + z2.imag);
    }
    static Complex operator-(Complex z1, Complex z2) {
        return Complex(z1.real - z2.real, z1.imag - z2.imag);
    }
    
    String^ ToString() override {
        if (imag < 0.0)
            return String::Format("({0} - {1}i)", real, -imag);
        else if (1.0/imag == Double::NegativeInfinity)  // imag == 0.0
            return String::Format("({0} - 0.0i)", real);
        else
            return String::Format("({0} + {1}i)", real, imag);
    }
};

關鍵技術點

  • initonly + 靜態建構函數:實現唯讀靜態常數(readonly 需常數運算式,值型別不適用)
  • IEEE 754 零表示:所有位元為 0,安全使用預設初始化
  • 運算子以值傳遞/回傳,符合值型別語意
  • Double::NegativeInfinity 檢測 +0.0/-0.0

測試程式與輸出


int main() {
    Complex c1;                    // (0 + 0i)
    Complex c2(12.5);              // (12.5 + 0i)
    Complex c3(-1.23, -4.5);       // (-1.23 - 4.5i)
    Complex c4 = c2 + c3;          // (11.27 - 4.5i)
    Complex c5 = c2 - c3;          // (13.73 + 4.5i)
    
    Console::WriteLine("c1: {0}", c1);
    Console::WriteLine("c2: {0}", c2);
    Console::WriteLine("c3: {0}", c3);
    Console::WriteLine("c4: {0}", c4);
    Console::WriteLine("c5: {0}", c5);
    Console::WriteLine("i: {0}", Complex::i);
    Console::WriteLine("c3.Real: {0}", c3.Real);
    Console::WriteLine("c3.Imag: {0}", c3.Imag);
}

c1: (0 + 0i)
c2: (12.5 + 0i)
c3: (-1.23 - 4.5i)
c4: (11.27 - 4.5i)
c5: (13.73 + 4.5i)
i: (0 + 1i)
c3.Real: -1.23
c3.Imag: -4.5

值型別設計限制

值型別不應包含:

  • 本地 C++ 陣列、本地類別型別、位元欄位
  • 區域類別的成員函數
  • friend 成員
  • 解構函數

參數傳遞:可傳值、傳址、傳參考、追蹤參考。

包含控制代碼的值型別:清理挑戰

值型別可包含 int*(本地指標)或 String^(GC 控制代碼)。超出作用域時,不會自動呼叫清理邏輯。若包含非平凡資源,建議改用參考型別並實作 IDisposable。

總結

值型別是高效能小型資料結構的最佳選擇:無 GC 壓力、語意清晰、支援運算子多載、靜態實例合法。核心權衡:無繼承、無自訂預設建構、無自訂拷貝/指派、無解構函數。適用場景:座標點、複數、日期時間、矩陣、色彩結構等「數值語意」型別。

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