程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Stan Lippman:C++/CLI全景體驗(1)

Stan Lippman:C++/CLI全景體驗(1)

編輯:C++入門知識
最近我訪問了中國的上海和北京,參加在兩地舉辦的微軟 Tech-ED 技術大會,在那裡我非常榮幸地向大家介紹了我們在 C++/CLI 方面的工作。大家的反饋非常之好,非凡是中國年輕一代程序員對 C++/CLI 的熱愛和理解給我留下了深刻的印象。在那裡,我還熟悉了來自上海的一位開發人員,同時也是一位技術作者, 李建忠 先生。我們經過討論之後決定合作撰寫一系列 C++/CLI 方面的文章,並以“C++/CLI全景體驗”專欄的形式獨家授權於中國《程序員》雜志發表。這篇短文旨在為大家簡單介紹一下我們寫作這個專欄的一些背景——有點電影中“定場鏡頭”的味道。 面對 C++/CLI ,很多人的第一個問題自然是“什麼是 C++/CLI ”,我個人喜歡將其看作是位於靜態程序設計和動態程序設計之間的一座橋梁。 C++/CLI 這個名稱本身就包含著一組術語——而其中最重要的術語卻是最不明顯的那一個。 首先來看第一個術語“ C++ ”,這當然指的是由 Bjarne Stroustrup 在 Bell 實驗室時發明的 C++ 編程語言。它所支持的是一種為代碼執行速度和執行體所占空間所高度優化的靜態對象模型。除了堆內存分配以外,它不支持在運行時對應用程序進行任何的更改。它答應我們對底層機器進行無限的訪問,但對於正在運行的程序中的活動類型、以及相關的程序基礎構造,它的訪問能力卻非常有限、或者根本就不可能。它是一門非常成功的編程語言,但是它卻不能適應目前的 Web 編程環境以及相關的安全問題——這已經成為目前程序設計中一個越來越重要的考量。 再來看第三個術語“ CLI ”,即通用語言基礎構造( Common Language InfrastrUCture ),這是一個支持動態組件編程模型的多層架構。在許多方面,它所表示的對象模型和 C++ 的完全相反。在 CLI 中,存在一個運行時軟件層(即虛擬執行環境)運行在應用程序和底層操作系統之間,應用程序代碼對底層機器的訪問會受到相當嚴格的限制;事實上, CLI 根本不答應安全環境中的代碼進行這樣的訪問。但另一方面, CLI 卻答應我們對正在運行的程序中的活動類型、以及相關的程序基礎構造進行完全的訪問,甚至答應我們動態構造額外的類型和程序基礎構造。這些靈活性的獲得當然伴隨有相當的空間(執行體所占空間)和時間(程序執行效率)代價,但是它卻解決了日益增長的基於連接的計算環境中所面臨的問題和需要。 最後,再來看第二個術語,即中間的斜線“ / ”,它往往為人們所忽略。其表示對 C++ 和 CLI 的一種綁定( binding ),它正是 C++/CLI 設計的焦點所在。據此,對於“什麼是 C++/CLI ”這一問題可能的一種答案便是“它是對靜態 C++ 對象模型和動態 CLI 組件模型的一種綁定”。 對於 C++/CLI ,一個 C++ 程序員只需要將其添加到她 [ 譯注 1] 已有的編程工具箱中就可以了。要成為一個 C++/CLI 程序員,你無需放棄任何已有的東西,雖然你要步入一個新的技術世界,你仍然需要學習它——但願你能享受這一過程,至少我知道我是這樣的。由此觀之,我們還可以將 C++/CLI 看作是一扇通往另一個世界的大門。 C++/CLI 將動態的、基於組件的編程模型和 ISO-C++ 集成在了一起,這種集成非常類似於我們當年在 Bell 實驗室對使用模板的泛型編程和當時的 C++ 所做的集成。在兩種情況下,你已有的代碼投資和編碼經驗都將得到保留。這是我們設計 C++/CLI 時一個基本的需求。 通用語言基礎構造( CLI )是一個多層的體系架構,它為所有 CLI 語言提供了各種各樣的服務。例如 CLI 中定義了一個通用類型系統( Common Type System ,簡稱 CTS ),而各個 CLI 語言都提供了自己對 CTS 的一個映射。該類型系統由一個根基類開始被組織為一個完整的類繼續體系。實際上,每一個 CLI 類型都是一個類——不僅包括像 integer 、 double 這樣的數值類型,而且也包括字面常量( literal constant )。每一個 CLI 類型(或者值)都表示一種 Object (所有 CLI 類型的根基類),比如數值 3.14159 、比如字符串常量 "Homer Simpson" 。 單一的根基類為運行時類型查詢和代碼生成(通常被稱為反射)提供了支持機制 [ 譯注 2] ,這是 ISO-C++ 所缺乏的。我們將在今後一系列文章中具體討論它們給 CLI 帶來的動態編程特性。 除此之外, CLI 還支持一種被稱作特性元數據( attribute metadata )的構造,它答應我們定義一些特性類,然後將其關聯在 CLI 類型和當前正在運行的程序構造上——這有效地擴展了內建於 CLI 中的類型和程序構造。這些用戶定義的特性也可以通過反射機制來獲得,應用程序則可以根據它們的值來進行條件邏輯判定。這也是 C++/CLI 為 C++ 帶來的動態組件編程的一部分。再次強調一遍,類型反射和特性將在我們的專欄中得到深入的討論。 那麼,對於大家來說怎樣學習 C++/CLI 呢?學習 C++/CLI 的其中一個要點便是學習底層的通用類型系統( CTS ),它包括以下三種類型: 1. 多態引用類型,其用於所有的類繼續。我們將在早期的一些專欄文章中討論它們。 2. 非多態值類型,其用於實現一些類似於數值類型那樣的、對運行時效率要求比較高的類型。我們將其放在引用類型之後討論。
   3. 抽象接口類型,其用於定義一組供引用類型或者值類型實現的操作。接口為多繼續提供了一種別樣的設計模式。我們也將有一系列專欄文章來討論它們。 將 CTS 映射為一組語言內置類型對於所有的 CLI 語言都適用,雖然各種語言所使用的語法各不相同。這也是一門 CLI 語言所要面對的第一個設計層面。例如,在 C# 中,我們可以用以下代碼來定義一個抽象基類型 Shape (一些具體的幾何對象將繼續自它)。 public abstract class Shape {…} 而在 C++/CLI 中,我們用下面的代碼來定義同樣的類型。 public ref class Shape abstract {…}; 除了語法差異之外,兩種聲明的實際表示完全相同。類似地,在 C# 中,我們可以用下面的代碼來定義一個具體類 Point2D 。 public struct Point2D {…} 而在 C++/CLI 中,我們用下面的代碼來定義同樣的類型。 public value class Point2D {…}; 我們對語法的選擇基於如下的出發點:以一種直觀的設計視角將 CLI 類型和 ISO-C++ 類型緊密地集成在一起。 因此,簡單地說一種語言比另一種語言更接近底層 CLI 並不正確。相反,每一門 CLI 語言都只是表達了自己對底層 CLI 對象模型的一種視圖。 學習 C++/CLI 的第二個要點是學習我們選擇直接提供給程序員操作的那些底層 CLI 元素。例如, CLI 為所有語言都提供了垃圾收集服務。一門語言不能選擇是否支持垃圾收集,而只能選擇如何更好地提供該服務。
   在 CLI 中,一個引用類型的所有對象都只能被分配在 CLI 托管堆上。這意味著 C++/CLI 支持兩種動態堆——本地堆(沒有任何形式的自動內存回收機制),和 CLI 托管堆。對於這兩種動態堆,開發人員通常要用某種形式的 new 操作符來分配對象;假如操作成功,對象在堆中初始位置的地址將被返回。但是兩者又有所區別,這是因為 CLI 托管堆中對象的位置有可能在垃圾收集器的清除以及隨後的壓縮中被重新調整。假如一個對象的位置被重新調整,那麼 CLI 運行時中所含的其中一項服務會透明地更新所有引用該對象的指代品( thingee )。 這就使得我們面臨著一種困難的選擇:我們是將這些指代品稱為指針,並且繼續用指針的語法來表示它們呢?還是引入一種新的類似的語法來表示它們需要非凡的處理?我們最後決定采用後者,看下面的代碼: N *pn = new N; R ^rn = gcnew R; 這裡, N 表示一個本地類型,而 R 表示一個 CLI 引用類型,帽子狀的符號( ^ )表示相關的地址是一個托管堆上的追蹤句柄( tracking handle )——也就是說,對象位置的任何重新調整都會被 CLI 所追蹤,相應的句柄也會被透明地更新。其中要害字 gcnew 在這裡被用作與 CLI 托管堆打交道的 new 表達式。 值類型事實上也可以位於托管堆上,雖然這並非必須。當它們作為一個引用類型的成員時,就會出現這種情況。假如我們答應獲取一個引用類型內部成員的地址,那麼本地指針也是不合適的,因為這些成員的位置也需要被追蹤。一種解決方法是簡單地禁止該項功能。這樣語言當然會變得更加簡單,但是同時語言也會變得更弱——例如我們將不能通過增長元素的地址值來遍歷 CLI 數組,這是因為 CLI 數組是一個引用類型,其內的元素都位於托管堆上。不提供這樣的功能意味著 CLI 數組將不能適用於標准模板庫( STL )中的 iterator 模式以及泛型算法。對於一個 C++ 程序員來說,這是不可接受的。 支持獲取可能位於托管堆中的值類型的地址同樣需要引入一種追蹤指針,我們稱之為追蹤內部指針( tracking interior pointer )。另外,我們還支持追蹤引用( tracking reference )這樣的概念——它具有類似本地引用的別名語義,但是它會在必要的時候被 CLI 透明地更新。最後,我們還支持一種固定指針( pinning pointer )的概念,它可以在該指針的作用范圍內阻止垃圾收集器移動其所引用的對象。 這些新的符號及其表示的復雜的間接類型是在我們對托管堆反復學習和熟悉之後產生的。面對生存期短暫的托管堆對象,我們需要某種精巧的方式來熟悉和使用它們,我們相信這些額外的間接類型可以給大家很多幫助。我們將在今後的專欄文章中具體討論它們。 我們在此對一門 CLI 語言所選擇的第二個設計層面表示了其對底層 CLI 實現模型的一層映射。選擇什麼樣的映射取決於該編程語言定位於什麼樣的程序及程序員模型。當你選擇一門 CLI 語言進行編程的時候,你實際上也是在選擇遵從一種程序員模型。我們對於 C++/CLI 程序員的定位是那些歷練較深的系統程序員,這些程序員通常所面對的任務是為高層的
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved