C++/CLI可以說是標準C++語言一種新的"方言",它是Microsoft為充分利用CLI(Common Language Infrastructure)平台而開發出來的。那麼,它在語言方面有何新穎獨到之處呢,下面,就讓我們一起開始奇妙的C++/CLI語言之旅(文中所有範例程式碼,均以Visual Studio.NET 2005 Professional編譯通過,所有的講解內容,也均以Visual Studio.NET 2005環境為基礎)。
程式集與中繼資料
傳統的C++編譯模式包括把單獨的源檔案編譯為目標檔案(obj),再把目標檔案與庫函數連結在一起,以產生可執行程式。而CLI模式卻大不相同,它涉及到程式集的建立與使用。
簡單來說,在不計輸入源檔案數目的基礎上,程式集即為單次編譯的輸出。如果輸出帶有一個進入點函數(例如main函數),它即為一個.exe檔案;如果沒有,它則為一個.dll檔案。任何引用外部程式集而產生的編譯,必須要訪問所依賴的程式集,此時也沒有類似傳統連結時用到的標頭檔機制,而是通過編譯器在所依賴的程式集內部尋找,來訪問所需的外部資訊。
程式集包含了中繼資料,其描述了包含在那裡的類型與函數,還有CIL(Common Intermediate Language)指令--Microsoft稱其為"MSIL"。中繼資料與指令能通過獨立的VES(Virtual Execution System)來執行。
CLI類型
例1是一個類比二維點的類。此處不得不提到命名空間,所有的CLI標準庫類型都屬於System命名空間,或嵌套在其內部的某個命名空間之下,例如System::Object和System::String,還有System::IO、 System::Text、System::Runtime::CompilerOptions等等。標記1可避免在程式中一直使用namespace限定詞。
例1:
/*1*/
using namespace System;
/*2*/
public ref class Point
{
int x;
int y;
public:
//定義用於讀寫X與Y執行個體屬性
/*3a*/ property int X
{
/*3b*/ int get() { return x; }
/*3c*/ void set(int val) { x = val; }
}
/*4a*/ property int Y
{
/*4b*/ int get() { return y; }
/*4c*/ void set(int val) { y = val; }
}
//定義執行個體建構函式
/*5a*/ Point()
{
/*5b*/ X = 0;
/*5c*/ Y = 0;
}
/*6a*/ Point(int xor, int yor)
{
/*6b*/ X = xor;
/*6c*/ Y = yor;
}
//定義執行個體方法
/*7a*/ void Move(int xor, int yor)
{
/*7b*/ X = xor;
/*7c*/ Y = yor;
}
/*8a*/ virtual bool Equals(Object^ obj) override
{
/*8b*/ if (obj == nullptr)
{
return false;
}
/*8c*/ if (this == obj) //我們在測試自己嗎?
{
return true;
}
/*8d*/ if (GetType() == obj->GetType())
{
/*8e*/ Point^ p = static_cast<Point^>(obj);
/*8f*/ return (X == p->X) && (Y == p->Y);
}
return false;
}
/*9*/ virtual int GetHashCode() override
{
return X ^ (Y << 1);
}
/*10a*/ virtual String^ ToString() override
{
/*10b*/ return String::Concat("(", X, ",", Y, ")");
}
};
在標記2中,我們定義了一個稱為Point的引用類(ref class),一個引用類是一個CLI參考型別,當兩者一起使用時,ref與class(中間有空格)表示了一個新的關鍵詞。