程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> C++:最強大的.NET語言之對象構造

C++:最強大的.NET語言之對象構造

編輯:vc教程
簡介

  Visual C++開發小組花了大量的時間用於聽取用戶的意見,在對 .NET和C++經過仔細考量之後,決定在Visual C++ 2005中重新設計對通用語言運行時庫(CLR)的支持,此項重新的設計被稱為"C++/CLI",它將為使用及編寫CLR類型提供更自然的語法。在本文中,主要探討了新的語法,並將之與C#和托管C++這兩個CLR平台上極其相近的語言進行比較,在文中也會適當地以圖表給出其與本地C++的相似之處。

  通用語言運行時庫(CLR)包括了一組規范,其是Microsoft .NET的基礎,也是CLI的Microsoft版本實現。C++/CLI語言設計的目標是為了對CLI提供更自然的C++支持,而Visual C++ 2005的編譯器則在CLR上實現了C++/CLI。

  當在仔細研究了Visual C++ 2005編譯器和C++/CLI語言設計之後,就會發現它們傳達了兩條重要的訊息;首先,Visual C++把自己定位於在CLR平台上的最低級編程語言,(看起來似乎沒有必要使用其他語言了--包括MSIL);其次,.NET編程應與本地C++編程一樣自然。

  本文針對C++程序員,但並不想說服你放棄C#或者Visual Basic .NET。如果你非常喜歡C++,並想繼續使用傳統C++提供的全部功能,而又想要C#般的編程效率,那本文正適合你。另外,本文並不是CLR或 .NET Framework的簡介,而把重點放在Visual C++ 2005是怎樣使你可以編寫 .NET Framework上更優雅和高效的代碼。

  對象構造

  CLR定義了兩種類型:值類型和引用類型。值類型被設計用於可進行高效地分配和訪問,它們與C++的內置類型大體相似,你也能創建屬於你自己的類型,這就是Bjarne Stroustrup所稱的具體類型;另一方面,引用類型被設計用於提供面向對象編程所需的特性,可用於創建有著層次結構的類:例如派生類和虛擬函數。另外在CLR中,引用類型自始至終都提供了額外的運行時特性,如自動內存管理--通常稱為垃圾回收。同時,對引用類型和值類型,CLR也提供了精確的運行時類信息,這種特性通常被稱為反射。

  值類型分配在堆棧上;而引用類型通常分配在托管堆中--這是由CLR垃圾回收機制所管理的堆。如果你在C++中編寫匯編代碼,如平時那樣,可在CRT堆中分配本地C++類型,在將來,Visual C++開發小組甚至允許你在托管堆中分配本地C++類型,畢竟,垃圾回收對本地類型來說,也是一個極具吸引力的主題。

  本地C++允許選擇在何處創建一個特定的對象,任何類型都可分配在堆棧或CRT堆中。

// 分配在堆棧上
std::wstring stackObject;

// 分配在CRT堆中
std::wstring* heapObject = new std::wstring;
   如上所示,在何處分配對象是獨立於類型的,主動權完全掌握在程序員的手中。另外,堆棧與堆的分配語法也是易於區別的。

  另一方面,C#通常是在堆棧上創建值類型,而在托管堆中創建引用類型。下例中使用的System.DateTime類型,被聲明為值類型。

// 分配在堆棧上
System.DateTime stackObject = new System.DateTime(2003, 1, 18);

// 分配在托管堆中
System.IO.MemoryStream heapObject = new System.IO.MemoryStream();
  如上例所示,聲明對象的方式並沒有指出對象分配在堆棧上或托管堆中,其完全取決於程序編寫者和運行時庫。

  C++的托管擴展--簡稱為托管C++,可在本地C++代碼中混合托管代碼。為了遵循C++標准,C++被加入了擴展,以提供對CLR的全面支持。不幸的是,正是因為有太多的擴展,所以如果要用C++來編寫大量的托管代碼,就成了一件異常痛苦的事。

//分配在堆棧上
DateTime stackObject(2003, 1, 18);

//分配在托管堆中
IO::MemoryStream __gc* heapObject = __gc new IO::MemoryStream;
  在C++程序員看來,在堆棧上分配一個值類型看起來非常正常,而在托管堆中的分配方式,看起來就有點怪:__gc是托管C++擴展中的一個關鍵字,有意思的是,在某些情況下,托管C++能推斷你的意思,所以上述例子可重寫為不帶__gc關鍵字。

//分配在托管堆中
IO::MemoryStream* heapObject = new IO::MemoryStream;
  這樣看起來更像本地C++代碼了--但heapObject並不是一個真正的C++指針。C++程序員通常傾向於在指針中保存一個不變的數值,但垃圾回收器會在任何時候,在內存中移動對象。另一個不足之處是,不能僅僅依靠查看代碼,就能確定對象是分配在本地還是托管堆中,必須知道程序編寫者是怎樣定義一個類型的。

  C++/CLI為此引入了句柄的概念,以便把CLR對象引用與C++指針區別開來。少了C++指針含義的重載,語言中也少了很多歧義,另外,通過句柄,對CLR也能提供更加自然的支持,例如,你能在C++中,直接對引用類型使用操作符重載,因為此時句柄已經能支持操作符重載了。由於C++禁止指針操作符重載,如果沒有"托管"指針,這幾乎不可能實現。

//分配在堆棧上
DateTime stackObject(2003, 1, 18);

//分配在托管堆中
IO::MemoryStream^ heapObject = gcnew IO::MemoryStream;
  相對於值類型聲明來說,和以前沒什麼不同,但對引用類型聲明來說,變化卻很明顯,操作符 ^ 把變量聲明為對一個CLR引用類型的句柄。當垃圾回收器在內存中移動被引用的對象時,同時也會自動更新句柄的值。另外,它們是可重綁定的,這允許它們可像C++指針那樣指向不同的對象。另外需注意的一件事是,操作符gcnew已經代替了操作符new,清楚地指明了對象被分配在托管堆中。對托管類型,操作符new已經不能被重載(此處並非語帶雙關),只能把對象分配在CRT堆中,除非你提供自己重寫的new操作符。

  簡而言之:本地C++指針已經與CLR對象引用大不相同了。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved