C++/CLI 採用組件(Assembly)而非標頭檔共享型別資訊,改變了傳統 C++ 的編譯連結模型。本文探討標頭檔角色變化、內聯函數跨組件行為、CLI 陣列語法與語意、以及值型別與參考型別的關鍵差異。
傳統 C++:型別定義放在 .h,實作放在 .cpp,透過 #include 共享宣告。
C++/CLI:型別編譯成 .dll 組件,包含完整中繼資料。使用者 #using "Point.dll" 即可存取完整型別定義,無需標頭檔。
// Point.cpp - 單一來源檔編譯成 Point.dll
public ref class Point {
// ...
virtual int GetHashCode() override; // 宣告
};
int Point::GetHashCode() override { // 定義:必須在同一檔案
return X ^ (Y << 1);
}
原因:編譯組件時需存取該組件本身的中繼資料,若定義分離至另一檔案,會產生循環依賴。
inline 提示編譯器展開呼叫,以空間換時間get_X/set_X)可標記 inlineGetHashCode、Equals)不建議跨組件內聯override 函數不能標記 inlineunsigned int, 指標, const, volatileget_PropertyName/set_PropertyName,無運算子多載概念的語言也能呼叫op_Addition, op_Equality 等參考型別相等性比較應實作 Equals,而非單靠 ==:
Equals 為虛擬函數,支援多型比較== 為靜態運算子,無多型Equals 會繼承 Object::Equals(參考相等性)
public ref class Point {
public:
static bool operator==(Point^ p1, Point^ p2) {
Object^ o1 = p1; // 隱式轉換避免遞迴
Object^ o2 = p2;
if (o1 == nullptr || o2 == nullptr) return false;
if (o1 == o2) return true; // 同一參考
if (p1->GetType() == p2->GetType()) {
return (p1->X == p2->X) && (p1->Y == p2->Y);
}
return false;
}
};
關鍵:使用 Object^ 比較 nullptr 與參考相等性,避免觸發自訂 == 導致遞迴。
int main() {
// 一維陣列:指定大小 + 初始化清單
array^ numbers = gcnew array(5) {10, 20, 30, 40}; // 第 5 元素預設 0
// 一維陣列:僅初始化清單(大小推導)
array^ points = gcnew array {gcnew Point(3,4), gcnew Point(5,7)};
// 重新指派:相同型別、不同大小
numbers = gcnew array {55, 66, 77}; // 3 元素
numbers = gcnew array {}; // 0 元素
// 元素存取
points[0]->Move(2,5); // 修改現有物件
points[1] = gcnew Point(8,1); // 替換參考
}
generic
void Display1DArray(String^ text, array^ ary) {
if (ary == nullptr) {
Console::WriteLine("nullptr passed");
return;
}
Console::Write("{0} {1}:", text, ary->Length);
for each (T element in ary) { // for each 遍歷集合
Console::Write(" {0}", element);
}
Console::WriteLine();
}
ary->Length:唯讀屬性,取得元素總數for each:編譯器轉換為列舉器模式,支援所有 IEnumerable 型別System::Array::Item 索引屬性
int main() {
// 2 維陣列:2 列 3 行
array^ names = gcnew array(2, 3) {
{"John", "Robert", "Peter"},
{"Mary", "Alice"} // 第 2 列第 3 行為 nullptr
};
Console::WriteLine("elements: {0}", names->Length); // 6
Console::WriteLine("dimensions: {0}", names->Rank); // 2
Console::WriteLine("names[0,0]: {0}", names[0,0]); // John
// 重新指派不同大小的同維度陣列
names = gcnew array(5, 7); // 35 元素,全 nullptr
Console::WriteLine("elements: {0}", names->Length); // 35
}
Rank:維度數(1=一維,2=二維...)Length:所有維度元素總數arr[i,j] 而非 arr[i][j]
// 簽名:... array^
static String^ Concat(... array
Int32::MaxValue:對應 C++ int 最大值 2,147,483,647int→Int32, long long→Int64, float→Single, double→Double| 概念 | 傳統 C++ | C++/CLI |
|---|---|---|
| 型別共享 | 標頭檔 | 組件中繼資料 |
| 跨模組內聯 | 連結期/編譯期 | JIT 執行期(版本脆弱) |
| 陣列記憶體 | 堆疊/堆,固定大小 | GC 堆,動態大小,邊界檢查 |
| 多維陣列 | 陣列的陣列 | 真正多維(連續記憶體) |
| 參數陣列 | va_list / initializer_list | ... array |