值型別(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/struct | ref class/struct |
| 基底類別 | System::ValueType (隱式 sealed) | System::Object |
| 記憶體管理 | 堆疊/內嵌,非 GC | GC 堆 |
| 繼承 | 不可繼承 (sealed) | 可繼承 |
| 預設建構函數 | 隱式(全零初始化),不可自訂 | 可自訂 |
| 拷貝/指派 | 隱式逐位複製,不可多載 | 無預設,需手動實作 |
| 靜態實例 | 允許 | 禁止 |
this 型別 | interior_ptr<T> | T^ |
int→0, bool→false, handle→nullptr值型別傳遞給 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;
}
// 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) { ... }
建議:只保留一個版本避免多載解析歧義。以值傳遞版最符合值型別語意。
| C++/CLI 型別 | CLI 值型別 |
|---|---|
bool | System::Boolean |
wchar_t | System::Char |
signed char | System::SByte |
unsigned char | System::Byte |
char | System::SByte 或 System::Byte |
short | System::Int16 |
unsigned short | System::UInt16 |
int | System::Int32 |
unsigned int | System::UInt32 |
long long | System::Int64 |
unsigned long long | System::UInt64 |
float | System::Single |
double | System::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 需常數運算式,值型別不適用)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
值型別不應包含:
friend 成員參數傳遞:可傳值、傳址、傳參考、追蹤參考。
值型別可包含 int*(本地指標)或 String^(GC 控制代碼)。超出作用域時,不會自動呼叫清理邏輯。若包含非平凡資源,建議改用參考型別並實作 IDisposable。
值型別是高效能小型資料結構的最佳選擇:無 GC 壓力、語意清晰、支援運算子多載、靜態實例合法。核心權衡:無繼承、無自訂預設建構、無自訂拷貝/指派、無解構函數。適用場景:座標點、複數、日期時間、矩陣、色彩結構等「數值語意」型別。