第11章-C CLI程序設(shè)計(jì)基礎(chǔ)_第1頁(yè)
第11章-C CLI程序設(shè)計(jì)基礎(chǔ)_第2頁(yè)
第11章-C CLI程序設(shè)計(jì)基礎(chǔ)_第3頁(yè)
第11章-C CLI程序設(shè)計(jì)基礎(chǔ)_第4頁(yè)
第11章-C CLI程序設(shè)計(jì)基礎(chǔ)_第5頁(yè)
已閱讀5頁(yè),還剩70頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

C++程序設(shè)計(jì)第11章C++/CLI程序設(shè)計(jì)基礎(chǔ)第11章C++/CLI程序設(shè)計(jì)基礎(chǔ)VisualC++2010不僅能用ISO標(biāo)準(zhǔn)C++開(kāi)發(fā)直接運(yùn)行于Windows操作系統(tǒng)之上的應(yīng)用程序,也能設(shè)計(jì)基于.NET平臺(tái)的應(yīng)用程序。微軟公司對(duì)標(biāo)準(zhǔn)C++進(jìn)行了擴(kuò)展,專(zhuān)門(mén)為.NET平臺(tái)設(shè)計(jì)了C++/CLI,目的是使廣大VisualC++程序員可以用C++語(yǔ)言方便地創(chuàng)建運(yùn)行于.NET框架之上的應(yīng)用程序。本章重點(diǎn)介紹C++/CLI為.NET平臺(tái)上的程序設(shè)計(jì)對(duì)標(biāo)準(zhǔn)C++所做的擴(kuò)展,主要內(nèi)容有值類(lèi)型、引用類(lèi)型、裝箱與拆箱、托管數(shù)組、句柄、托管類(lèi)、接口與多態(tài)、枚舉、異常、模板與泛型、委托與事件等C++/CLI基礎(chǔ)知識(shí)和.NET托管代碼編程技術(shù)。11.1概述

11.2C++/CLI的基本數(shù)據(jù)類(lèi)型

11.3C++/CLI的句柄、裝箱與拆箱

11.4C++/CLI的字符串和數(shù)組

11.5C++/CLI中的類(lèi)和屬性

第11章C++/CLI程序設(shè)計(jì)基礎(chǔ)11.6C++/CLI中的多態(tài)與接口

11.7C++/CLI中的模板和泛型

11.9C++/CLI中的枚舉

11.8C++/CLI中的異常

11.10.NET中的委托與事件11.1概述.NET平臺(tái)是微軟公司為簡(jiǎn)化在第三代互聯(lián)網(wǎng)的分布式環(huán)境下應(yīng)用程序的開(kāi)發(fā),基于開(kāi)放互聯(lián)網(wǎng)標(biāo)準(zhǔn)和協(xié)議之上,實(shí)現(xiàn)異質(zhì)語(yǔ)言和平臺(tái)高度交互性而創(chuàng)建的新一代計(jì)算和通信平臺(tái)。.NET平臺(tái)主要由5個(gè)部分構(gòu)成:Windows.NET、.NET企業(yè)級(jí)服務(wù)器、.NETWeb服務(wù)構(gòu)件、.NET框架和VisualStudio.NET。

(1)Windows.NET是可以運(yùn)行.NET程序的操作系統(tǒng)的統(tǒng)稱(chēng),主要包括WindowsXP、WindowsServer2003、Windows7等操作系統(tǒng)和各種應(yīng)用服務(wù)軟件。(2).NET企業(yè)級(jí)服務(wù)器是微軟公司推出的進(jìn)行企業(yè)集成和管理的所有基于Web的各種服務(wù)器應(yīng)用的系列產(chǎn)品,包括ApplicationCenter2000、SQLServer2008、BizTalkServer2000等。

(3).NETWeb服務(wù)構(gòu)件是保證.NET正常運(yùn)行的公用性Web服務(wù)組件。(4).NET框架是.NET的核心部分,是支持生成和運(yùn)行下一代應(yīng)用程序和Web服務(wù)的內(nèi)部Windows組件。.NET框架的關(guān)鍵組件為公共語(yǔ)言運(yùn)行時(shí)(CommonLanguageRuntime,CLR)和.NET基礎(chǔ)類(lèi)庫(kù)(BasicClassLibrary,BCL),BCL中包括了大量用于支持ADO.NET、ASP.NET、Windows窗體和WindowsPresentationFoundation應(yīng)用開(kāi)發(fā)的類(lèi)。(5)VisualStudio.NET是用于建立.NET框架應(yīng)用程序而推出的應(yīng)用軟件開(kāi)發(fā)工具,其中包含C#.NET、C++.NET、VB.NET和J#等開(kāi)發(fā)環(huán)境,支持多種程序設(shè)計(jì)語(yǔ)言的單獨(dú)和混合方式的軟件開(kāi)發(fā)。11.1概述11.1概述

.NET平臺(tái)的整體環(huán)境結(jié)構(gòu)如圖11-1所示。.NET框架提供了托管執(zhí)行環(huán)境、簡(jiǎn)化的開(kāi)發(fā)和部署以及與各種編程語(yǔ)言的集成。

公共語(yǔ)言運(yùn)行時(shí)是.NET框架的基礎(chǔ),可以將其看作是一個(gè)在執(zhí)行時(shí)管理代碼的代理,它提供內(nèi)存管理、線程管理和遠(yuǎn)程處理等核心服務(wù),并且還強(qiáng)制實(shí)施嚴(yán)格的類(lèi)型安全以及可提高安全性和可靠性的其他形式的代碼準(zhǔn)確性。事實(shí)上,代碼管理的概念是運(yùn)行時(shí)的基本原則。以CLR為目標(biāo)的代碼稱(chēng)為托管代碼,而不以CLR為目標(biāo)的代碼稱(chēng)為非托管代碼。.NET框架的另一個(gè)主要組件是類(lèi)庫(kù),它是一個(gè)綜合性的面向?qū)ο蟮目芍赜妙?lèi)型集合,可以使用它開(kāi)發(fā)多種應(yīng)用程序,這些應(yīng)用程序包括傳統(tǒng)的命令行或圖形用戶(hù)界面(GraphicalUserInterface)應(yīng)用程序,也包括基于ASP.NET的網(wǎng)絡(luò)服務(wù)應(yīng)用程序,如Web窗體和XMLWeb服務(wù)。11.1概述11.1概述.NET框架可由非托管組件承載,這些組件將公共語(yǔ)言運(yùn)行時(shí)加載到它們的進(jìn)程中并啟動(dòng)托管代碼的執(zhí)行,從而創(chuàng)建一個(gè)可以同時(shí)利用托管和非托管功能的軟件環(huán)境。公共語(yǔ)言運(yùn)行時(shí)為多種高級(jí)語(yǔ)言提供了標(biāo)準(zhǔn)化的運(yùn)行環(huán)境,在VisualStudio.NET中能用于開(kāi)發(fā)的語(yǔ)言就有VisualBasic、C#、C++和J#。CRL的規(guī)范由公共語(yǔ)言基礎(chǔ)結(jié)構(gòu)(CommonLanguageInfrastructure,CLI)描述,其中包括了數(shù)據(jù)類(lèi)型、對(duì)象存儲(chǔ)等與程序設(shè)計(jì)語(yǔ)言相關(guān)的設(shè)計(jì)規(guī)范。CLI的標(biāo)準(zhǔn)化工作由歐洲計(jì)算機(jī)制造商協(xié)會(huì)(EuropeanComputerManufacturersAssociation,ECMA)完成并成為ISO標(biāo)準(zhǔn),它們分別是EMCA-335和ISO/IEC23271。11.1概述本質(zhì)上,CLI提供了一套可執(zhí)行代碼和它運(yùn)行所需要的虛擬執(zhí)行環(huán)境的規(guī)范,虛擬機(jī)運(yùn)行環(huán)境能使各種高級(jí)語(yǔ)言設(shè)計(jì)的應(yīng)用軟件不修改源代碼即能在不同的操作系統(tǒng)上運(yùn)行。CLR是微軟對(duì)CLI的一個(gè)實(shí)現(xiàn),也是目前最好的實(shí)現(xiàn),另一個(gè)實(shí)例是Novell公司的一個(gè)開(kāi)放源代碼的項(xiàng)目Mono。CLI主要包括通用類(lèi)型系統(tǒng)(CommonTypeSystem,CTS)、元數(shù)據(jù)(Metadata)、公共語(yǔ)言規(guī)范(CommonLanguageSpecification,CLS)、通用中間語(yǔ)言(CommonIntermediateLanguage,CIL)和虛擬執(zhí)行系統(tǒng)(VirtualExecutionSystem,VES)幾個(gè)部分。通用類(lèi)型系統(tǒng)是CLI的基礎(chǔ),它是一個(gè)類(lèi)型規(guī)范,定義了所有CLI平臺(tái)上可以定義的類(lèi)型的集合,所有基于CLI的語(yǔ)言類(lèi)型都是CTS的一個(gè)子集,目前C++/CLI是對(duì)CTS描述支持最好的高級(jí)語(yǔ)言。11.1概述元數(shù)據(jù)是描述其他數(shù)據(jù)的數(shù)據(jù)(DataAboutOtherData),或者說(shuō)是用于提供某種資源的有關(guān)信息的結(jié)構(gòu)數(shù)據(jù)(StructuredData)。在CLI中,用元數(shù)據(jù)描述和引用CTS定義的類(lèi)型,元數(shù)據(jù)以一種獨(dú)立于任何語(yǔ)言的形式存儲(chǔ),正是元數(shù)據(jù)賦予了組件自描述的能力。公共語(yǔ)言規(guī)范是用以確保所有CLI語(yǔ)言能夠互操作的一組規(guī)則,它定義了所有CLI語(yǔ)言都必須支持的一個(gè)最小功能子集。各CLI語(yǔ)言可以選擇自己對(duì)CTS的一部分的映射,但是為了確保不同語(yǔ)言的交互,至少應(yīng)該支持CLS所定義的最小功能集。通用中間語(yǔ)言是一種中性語(yǔ)言,更準(zhǔn)確地說(shuō),是一套與處理器無(wú)關(guān)的指令集合。任何.NET編程語(yǔ)言所編寫(xiě)的程序均被編譯成通用中間語(yǔ)言指令集,程序運(yùn)行時(shí)再通過(guò)JIT(Just-In-Time)實(shí)時(shí)編譯器映射為機(jī)器碼。

11.1概述虛擬執(zhí)行系統(tǒng)為CLI程序提供了一個(gè)在各種可能的平臺(tái)上加載和執(zhí)行托管代碼的虛擬機(jī)環(huán)境。它只是一個(gè)規(guī)范,.NET框架和Mono各有自己的實(shí)現(xiàn)。VisualC++2010開(kāi)發(fā)平臺(tái)支持Windows下多種應(yīng)用程序的設(shè)計(jì),如控制臺(tái)應(yīng)用程序、MFC本地窗體應(yīng)用程序、.NET窗體應(yīng)用程序、ActiveX控件等。11.2C++/CLI的基本數(shù)據(jù)類(lèi)型ISO標(biāo)準(zhǔn)C++中的基本數(shù)據(jù)類(lèi)型(如int、double、char和bool)在C++/CLI程序中可以繼續(xù)使用,但是它們已被編譯器映射到在System命名空間中定義的CLI值類(lèi)類(lèi)型(ValueClassType)。ISO標(biāo)準(zhǔn)C++基本類(lèi)型名稱(chēng)是CLI中相對(duì)應(yīng)的值類(lèi)類(lèi)型的簡(jiǎn)略形式。表11-1給出了基本數(shù)據(jù)類(lèi)型和對(duì)應(yīng)的值類(lèi)型,以及為它們分配的內(nèi)存大小。11.2C++/CLI的基本數(shù)據(jù)類(lèi)型基本數(shù)據(jù)類(lèi)型CLI值類(lèi)型大小(字節(jié))boolSystem::Boolean1char、singedcharSystem::SByte1unsignedcharSystem::Byte1shortSystem::Int162unsignedshortSystem::UInt162int、longSystem::Int324unsignedint、unsignedlongSystem::UInt324longlongSystem::Int648unsignedlonglongSystem::UInt648floatSystem::Single4double、longdoubleSystem::Double8wchar_tSystem::Char211.2C++/CLI的基本數(shù)據(jù)類(lèi)型在C++/CLI程序中,用基本數(shù)據(jù)類(lèi)型定義變量與CLI的簡(jiǎn)單值類(lèi)型定義變量等價(jià)。例如:doublevalue=2.5;//等價(jià)于System::Doublevalue=2.5;在VisualC++2010中,創(chuàng)建CLR控制臺(tái)應(yīng)用程序的方法與Win32控制臺(tái)應(yīng)用程序創(chuàng)建的過(guò)程基本類(lèi)似,主要不同點(diǎn)是在新建項(xiàng)目時(shí)選擇“CLR控制臺(tái)應(yīng)用程序”模板。在項(xiàng)目創(chuàng)建過(guò)程中,系統(tǒng)自動(dòng)為新建項(xiàng)目添加了主函數(shù),并且其中含有輸出“HelloWorld”字符串的輸出語(yǔ)句?!纠?1-1】設(shè)計(jì)CLR控制臺(tái)應(yīng)用程序,輸出變量的類(lèi)型信息。

11.2C++/CLI的基本數(shù)據(jù)類(lèi)型程序說(shuō)明:(1) 在CLR控制臺(tái)應(yīng)用程序中,本地C++的標(biāo)準(zhǔn)控制臺(tái)輸出和輸入方法(cout和cin)已不能使用,取而代之的是用Console類(lèi)進(jìn)行標(biāo)準(zhǔn)輸入和輸出。Console類(lèi)定義在System命名空間,其中標(biāo)準(zhǔn)輸出函數(shù)為WriteLine()和Write(),標(biāo)準(zhǔn)輸入函數(shù)為ReadLine()、Read()和ReadKey()。WriteLine(L“intx=100;類(lèi)型:{0}\t值:{1}”,x.GetType(),x)函數(shù)的花括號(hào){0}表示輸出0號(hào)參數(shù)x.GetType()的值,花括號(hào){1}表示輸出1號(hào)參數(shù)x的值。在花括號(hào)中還可以指定參數(shù)的格式化方式,格式化參數(shù)的設(shè)置方法可查閱聯(lián)機(jī)幫助。(2) 在程序的最后,插入了一條語(yǔ)句Console::Read();,該語(yǔ)句的作用是等待用戶(hù)輸入回車(chē)。如果沒(méi)有該語(yǔ)句,在編程環(huán)境中運(yùn)行程序,程序運(yùn)行后窗口被立即關(guān)閉,用戶(hù)不能觀察輸出結(jié)果,添加該語(yǔ)句后問(wèn)題得到解決。11.3C++/CLI的句柄、裝箱與拆箱與本地C++不同,CLR的托管內(nèi)存堆受到垃圾回收器(GarbageCollector)的管理。垃圾回收器使得程序員不必?fù)?dān)心對(duì)象是否釋放。CLR的垃圾回收器會(huì)定期運(yùn)行,觀察托管堆中的對(duì)象,并判斷它們是否仍然為程序所需。如果不再需要,該對(duì)象便被標(biāo)記為垃圾,最終由垃圾回收器回收所占據(jù)的內(nèi)存。垃圾回收器不僅用于收回已不再使用的內(nèi)存空間,還負(fù)責(zé)內(nèi)存“碎片”的整理,提高內(nèi)存的使用效率。

由于垃圾回收器的執(zhí)行,通常CLR程序的執(zhí)行速度要稍慢于人工管理內(nèi)存的程序。但是,這僅僅在實(shí)時(shí)性要求高的應(yīng)用程序中才是問(wèn)題,對(duì)于大多數(shù)對(duì)速度不是十分挑剔的程序,自動(dòng)內(nèi)存管理所帶來(lái)的優(yōu)勢(shì)是十分明顯的。11.3C++/CLI的句柄、裝箱與拆箱1.句柄(Handle)

本地C++用new關(guān)鍵字為對(duì)象在本地堆上分配內(nèi)存,并且返回一個(gè)新分配內(nèi)存的指針。類(lèi)似地,托管C++/CLI用gcnew關(guān)鍵字為托管對(duì)象在托管堆上分配內(nèi)存,并且返回一個(gè)指向這塊新內(nèi)存的句柄。如同new返回的地址需要一個(gè)指針變量保存它一樣,gcnew返回的句柄也需要有相應(yīng)的變量進(jìn)行存儲(chǔ)。CLR上的托管堆稱(chēng)為垃圾回收堆(Garbage-collectedHeap),在其上分配空間的關(guān)鍵字gcnew中的“gc”前綴的含義是指垃圾回收堆。11.3C++/CLI的句柄、裝箱與拆箱句柄類(lèi)似于本地C++指針,但也有很大區(qū)別。句柄確實(shí)存儲(chǔ)著托管堆上某個(gè)對(duì)象的地址,但由于CLR的垃圾回收器會(huì)對(duì)托管堆進(jìn)行壓縮整理,可能移動(dòng)存儲(chǔ)在托管堆中的對(duì)象,所以垃圾回收器會(huì)自動(dòng)更新句柄所包含的地址。與本地指針不同的是句柄不能像本地指針那樣執(zhí)行地址的算術(shù)運(yùn)算,也不允許對(duì)其進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。句柄的聲明使用符號(hào)^(發(fā)音hat),也不同于指針的聲明使用符號(hào)*。與指針變量的定義類(lèi)似,句柄變量的定義格式如下:<數(shù)據(jù)類(lèi)型>^<句柄變量名>;例如:Date^myHandle=gcnewDate(2010,4,19);表示用Date類(lèi)在托管堆上創(chuàng)建對(duì)象,并由句柄變量myHandle保存返回的句柄值。11.3C++/CLI的句柄、裝箱與拆箱在本地C++中,&運(yùn)算符返回一個(gè)指針。類(lèi)似地,在C++/CLI中,%運(yùn)算符把一個(gè)托管對(duì)象的內(nèi)存地址返回給一個(gè)句柄。這里需要注意的是:只有當(dāng)對(duì)象位于托管內(nèi)存中時(shí),才能使用%運(yùn)算符。下面的代碼在編譯時(shí)報(bào)告錯(cuò)誤: int^handle=nullptr; intx=100; handle=&x; //錯(cuò)誤nullptr是C++/CLI的一個(gè)關(guān)鍵字,表示向句柄賦空值。這里不能使用本地C++為指針賦空值的0或NULL。C++/CLI中,對(duì)句柄也可以使用運(yùn)算符*和->進(jìn)行間接訪問(wèn)。%與*運(yùn)算符是互逆操作,以任意順序?qū)⑺鼈冞B續(xù)應(yīng)用于同一個(gè)句柄,所產(chǎn)生的作用將相互抵消。11.3C++/CLI的句柄、裝箱與拆箱2.值類(lèi)型(ValueType)與引用類(lèi)型(ReferenceType)

區(qū)別于本地C++的數(shù)據(jù)類(lèi)型,C++/CLI的數(shù)據(jù)類(lèi)型稱(chēng)為托管類(lèi)型。托管類(lèi)型分值類(lèi)型和引用類(lèi)型兩類(lèi)。.NET框架結(jié)構(gòu)本可以將所有類(lèi)型設(shè)為引用類(lèi)型,支持值類(lèi)型的目的是避免處理整型和其他基本數(shù)據(jù)類(lèi)型時(shí)產(chǎn)生不必要的開(kāi)銷(xiāo)。值類(lèi)型定義的變量默認(rèn)情況下是在堆棧上分配空間,但也可以用gcnew操作符將其存儲(chǔ)在托管堆上。引用類(lèi)型的對(duì)象都在托管堆中分配內(nèi)存空間,然而為引用這些對(duì)象所創(chuàng)建的變量都必須是句柄,這些句柄是存儲(chǔ)在堆棧上的。例如,String類(lèi)型是引用類(lèi)型,引用String對(duì)象的變量必須是句柄。11.3C++/CLI的句柄、裝箱與拆箱在托管堆上分配的對(duì)象都不能在全局作用域內(nèi)聲明,也就是說(shuō),全局或靜態(tài)變量的類(lèi)型不能是托管類(lèi)型。例如:intx=100; //int為簡(jiǎn)單值類(lèi)型,默認(rèn)在堆棧上分配空間int^ihandle=gcnewint(123); //ihandle句柄,本身在堆棧上,引用堆上的值類(lèi)型對(duì)象Stringstr;//錯(cuò)誤!String為引用類(lèi)型,只能在堆上分配空間,正確格式:String^str="";3.裝箱(Boxing)與拆箱(Unboxing)在C++/CLI中,每種內(nèi)置數(shù)據(jù)類(lèi)型都對(duì)應(yīng)一種簡(jiǎn)單值類(lèi)型,如int對(duì)應(yīng)System::Int32。所有的值類(lèi)型都繼承于System::ValueType類(lèi),它是一種輕量級(jí)的C++/CLI類(lèi)機(jī)制,非常適合于小型的數(shù)據(jù)結(jié)構(gòu),且從語(yǔ)義的角度來(lái)看,與數(shù)值類(lèi)似。11.3C++/CLI的句柄、裝箱與拆箱由于System::ValueType類(lèi)派生于System::Object類(lèi),而System::Object類(lèi)是C++/CLI中所有類(lèi)的基類(lèi),因此所有簡(jiǎn)單類(lèi)型的值都可以賦值給一個(gè)Object類(lèi)型的對(duì)象。本質(zhì)上,值類(lèi)型無(wú)法轉(zhuǎn)換成引用類(lèi)型,但可以通過(guò)所謂的裝箱操作在托管堆中創(chuàng)建值類(lèi)型的引用類(lèi)型副本。裝箱是將值類(lèi)型的值賦給托管堆上新創(chuàng)建的對(duì)象,使該值類(lèi)型的值可以按照Object類(lèi)型的對(duì)象進(jìn)行操作。裝箱操作實(shí)現(xiàn)了值類(lèi)型向引用類(lèi)型的轉(zhuǎn)換,這種轉(zhuǎn)換有時(shí)是需要的。例如,當(dāng)將堆棧上的實(shí)參變量傳遞給類(lèi)類(lèi)型的函數(shù)形參時(shí),編譯器在托管堆上生成含有實(shí)參值的對(duì)象供函數(shù)調(diào)用。裝箱轉(zhuǎn)換既可以顯式地進(jìn)行,也可以隱式地自動(dòng)完成。11.3C++/CLI的句柄、裝箱與拆箱下面例子給出了隱式和顯式裝箱轉(zhuǎn)換的方法:intx=15; //在堆棧上生成變量x,其中值為15int^ihandle=x;//隱式裝箱,ihandle引用托管堆中的一個(gè)對(duì)象Object^xhandle=static_cast<Object^>(x); //顯式裝箱拆箱轉(zhuǎn)換是裝箱的逆操作,拆箱轉(zhuǎn)換可以把一個(gè)Object引用轉(zhuǎn)換為一個(gè)簡(jiǎn)單值。拆箱操作就是在堆棧中復(fù)制引用類(lèi)型。通用中間語(yǔ)言CIL包含裝箱與拆箱的指令。例如:inty=static_cast<int>(ihandle); //顯式地拆箱intz=*ihandle; //隱式地拆箱,ihandle是與z相同類(lèi)型的句柄

如果一個(gè)Object句柄實(shí)際上并沒(méi)有引用一個(gè)簡(jiǎn)單值類(lèi)型的值,試圖對(duì)其進(jìn)行拆箱轉(zhuǎn)換將會(huì)導(dǎo)致一個(gè)InvalidCastException異常。11.3C++/CLI的句柄、裝箱與拆箱【例11-2】C++/CLI的句柄、值類(lèi)型與引用類(lèi)型、裝箱與拆箱等基本概念解析。(a)(b)圖11-2例11-2的內(nèi)存跟蹤窗口11.3C++/CLI的句柄、裝箱與拆箱跟蹤與觀察:從圖11-2(a)的監(jiān)視1窗口可見(jiàn),與本地C++類(lèi)似,簡(jiǎn)單值類(lèi)型變量與句柄的地址前4位相同,表示存儲(chǔ)在內(nèi)存的同一塊區(qū)域中。句柄intHandle和number中保存的是地址,并且它們?cè)谙嗤牧硪粔K內(nèi)存空間中,與本地C++中的指針十分相似,另外這兩個(gè)句柄的類(lèi)型均為System::ValueType^。(2) 從圖11-2(b)的監(jiān)視2窗口可見(jiàn),句柄intHandle所引用的托管堆中對(duì)象的值為210,類(lèi)型為System::Int32,System::Object^是其基類(lèi)。對(duì)象中含有MaxValue和MinValue值,分別表示Int32能表示的最大值和最小值。MaxValue的值可使用Console::WriteLine(System::Int32::MaxValue);語(yǔ)句輸出。11.4C++/CLI的字符串和數(shù)組

在C++/CLI中,字符串和數(shù)組均屬于引用類(lèi)型,它們都在托管堆上分配內(nèi)存。字符串是System::String類(lèi)的對(duì)象,所有的數(shù)組對(duì)象都是隱式地繼承于System::Array類(lèi)。11.4.1C++/CLI中的String類(lèi)

C++/CLI中用String類(lèi)類(lèi)型來(lái)說(shuō)明字符串,所定義的字符串是Unicode字符的有序集合,用于表示文本。每個(gè)Unicode字符占用內(nèi)存中的兩個(gè)字節(jié),String對(duì)象是System::Char對(duì)象的有序集合。String對(duì)象的值是不可變的,一旦創(chuàng)建了該對(duì)象,就不能修改該對(duì)象的值??此菩薷牧薙tring對(duì)象的方法實(shí)際上是返回一個(gè)包含修改內(nèi)容的新String對(duì)象。如果需要修改字符串對(duì)象的實(shí)際內(nèi)容,應(yīng)使用System::Text::StringBuilder類(lèi)。與本地C++一樣,C++/CLI中的String對(duì)象是以null字符結(jié)尾,這使得String對(duì)象和本地C++字符串與字符數(shù)組具有極強(qiáng)的互操作性。與其他引用類(lèi)型對(duì)象的聲明相同,String對(duì)象的定義方式如下: String^msg="WellcometoC++/CLIprogramming!"; String^errorStr=gcnewString('輸入錯(cuò)誤!');String類(lèi)可以使用類(lèi)似于本地字符數(shù)組的方法索引字符串中的元素。此外,還提供了許多成員函數(shù)和運(yùn)行符重載函數(shù)實(shí)現(xiàn)字符串的復(fù)制、合并、比較、查找和替換等操作。下面通過(guò)示例演示String類(lèi)的基本用法,更詳盡的用法可參考聯(lián)機(jī)幫助?!纠?1-3】String類(lèi)的基本用法。11.4C++/CLI的字符串和數(shù)組程序說(shuō)明:(1) 程序的Console::WriteLine(“…is{0:B}”,…);語(yǔ)句中,{0:B}表示輸出格式為布爾值。此處使用了.NET框架的復(fù)合格式設(shè)置功能,將對(duì)象的值轉(zhuǎn)換為其文本表示形式,并將該表示形式嵌入字符串中。格式項(xiàng)的語(yǔ)法是{索引[,對(duì)齊方式][:格式字符串]},它指定了一個(gè)強(qiáng)制索引、格式化文本的可選長(zhǎng)度和對(duì)齊方式,以及格式說(shuō)明符字符的可選字符串,其中格式說(shuō)明符字符用于控制如何設(shè)置相應(yīng)對(duì)象的值的格式。例如:doublevalue=123.456;Console::WriteLine("value={0:C2}",value); //貨幣格式輸出Console::WriteLine("value={0:E}",value); //科學(xué)記數(shù)法格式輸出輸出內(nèi)容為:value=¥123.46value=1.234560E+00211.4C++/CLI的字符串和數(shù)組11.4C++/CLI的字符串和數(shù)組(2)在程序的最后幾個(gè)輸出語(yǔ)句中,用String類(lèi)的Replace和ToLower成員函數(shù)對(duì)字符串的內(nèi)容進(jìn)行替換或變換,但這種修改是不改變?cè)凶址械男畔⒌?,運(yùn)行結(jié)果的最后一行驗(yàn)證了myString3的內(nèi)容沒(méi)有改變。11.4.2C++/CLI中的數(shù)組C++/CLI數(shù)組與String一樣是引用類(lèi)型,在托管堆上程序可以定義一維數(shù)組、多維數(shù)組和不規(guī)則數(shù)組。與其他引用類(lèi)型相同,托管堆中的數(shù)組也需要通過(guò)句柄來(lái)訪問(wèn)。11.4C++/CLI的字符串和數(shù)組C++/CLI中使用array關(guān)鍵字定義托管數(shù)組,一維數(shù)組的定義方式://定義有10個(gè)單元的整型數(shù)組,每個(gè)單元的值為0array<int>^int1DArray=gcnewarray<int>(10);//定義有5個(gè)單元的整型數(shù)組,單元值依次為1、3、5、7、9array<int>^values={1,3,5,7,9};//定義20個(gè)單元的實(shí)型數(shù)組,每個(gè)單元值為0.0array<double>^doubleArray(gcnewarray<double>(20));多維數(shù)組的定義方法與一維數(shù)組類(lèi)似。一維數(shù)組實(shí)際上是維數(shù)為1的多維數(shù)組,缺省情況下,托管數(shù)組定義語(yǔ)句中的維數(shù)值即為1。多維數(shù)組的最大維數(shù)值為32。多維托管數(shù)組的定義方法://定義4行5列,共20個(gè)單元的二維整型數(shù)組array<int,2>^int2DArray=gcnewarray<int,2>(4,5);//定義48個(gè)單元的三維整型數(shù)組array<int,3>^int3DArray=gcnewarray<int,3>(2,4,6);11.4C++/CLI的字符串和數(shù)組一維數(shù)組存儲(chǔ)單元的訪問(wèn)方式與本地C++數(shù)組一樣,方括號(hào)中加索引值的方式引用存儲(chǔ)單元,并且索引的初值也是0。例如int1DArray[0]和int1DArray[3]表示訪問(wèn)數(shù)組的第1和第4個(gè)存儲(chǔ)單元。多維數(shù)組存儲(chǔ)單元的訪問(wèn)方式與本地C++數(shù)組不同,采用在一個(gè)方括號(hào)內(nèi)用逗號(hào)分隔索引值的方法。例如int2DArray[0,0]和int3DArray[1,3,4]。不規(guī)則數(shù)組有時(shí)又稱(chēng)為數(shù)組的數(shù)組、變長(zhǎng)數(shù)組或正交數(shù)組。相對(duì)地,上面所講的多維數(shù)組又稱(chēng)為矩形數(shù)組。不規(guī)則數(shù)組與本地C++在堆上創(chuàng)建動(dòng)態(tài)數(shù)組的方法相似,它是通過(guò)句柄、句柄數(shù)組和一維數(shù)組構(gòu)建長(zhǎng)度不等的托管數(shù)組。11.4C++/CLI的字符串和數(shù)組下面的語(yǔ)句是在托管堆中建立了一個(gè)行長(zhǎng)度不等的二維數(shù)組,其中第0行有兩個(gè)元素,第1行有一個(gè)元素,第2行有三個(gè)元素:

array<array<int>^>^jagged={ gcnewarray<int>{1,2}, gcnewarray<int>{3}, gcnewarray<int>{4,5,6} };jagged是保存在堆棧中的句柄,它引用了托管堆上有3個(gè)元素的array<int>類(lèi)型句柄數(shù)組,該數(shù)組的每個(gè)單元存儲(chǔ)了一個(gè)array<int>類(lèi)型的句柄,每個(gè)句柄所引用的一維數(shù)組的長(zhǎng)度互不相同,分別為2、1和3,故稱(chēng)為不規(guī)則數(shù)組。所有數(shù)組若訪問(wèn)越界,則會(huì)引發(fā)異常。11.4C++/CLI的字符串和數(shù)組例如,由于int3DArray數(shù)組中沒(méi)有int3DArray[2,3,4]單元,語(yǔ)句int3DArray[2,3,4]=10;將導(dǎo)致CLR拋出IndexOutOfRangeException類(lèi)型的異常。類(lèi)似地,語(yǔ)句jagged[1][1]=10;也引發(fā)相同的異常。foreach語(yǔ)句是C++/CLI新引入的一種循環(huán)語(yǔ)句,這種語(yǔ)句可用于對(duì)整個(gè)數(shù)組或集合進(jìn)行遍歷。語(yǔ)法格式如下: foreach(<迭代變量數(shù)據(jù)類(lèi)型><迭代變量>in<數(shù)組或容器>) <循環(huán)體>下面的程序段演示了用foreach遍歷數(shù)組元素的方法: array<int>^values={1,3,5,7,9}; inttotal=0; foreach(intnumberinvalues) total+=number;11.4C++/CLI的字符串和數(shù)組在CLR中,System::Array類(lèi)是所有數(shù)組的基類(lèi),并且其中定義了對(duì)數(shù)組進(jìn)行排序和查找的方法,用戶(hù)在程序中能非常方便地對(duì)托管數(shù)組進(jìn)行排序或查找等操作。【例11-4】托管數(shù)組的應(yīng)用示例。程序說(shuō)明:(1)用Array::Sort函數(shù)可對(duì)數(shù)組進(jìn)行排序。Array中的Sort函數(shù)有個(gè)重載版本,具有對(duì)兩個(gè)數(shù)組進(jìn)行同步排序的功能。Array中另一個(gè)有用的函數(shù)是BinarySearch,其功能是在一維數(shù)組中搜索指定元素,并返回元素的索引位置。(2)二維數(shù)組matrix元素索引采用[i,j]方式,與本地C++的[i][j]方式不同,托管多維數(shù)組的數(shù)據(jù)是依次連續(xù)地存儲(chǔ)在一個(gè)段中,訪問(wèn)元素的速度可能要快于不規(guī)則數(shù)組。11.5C++/CLI中的類(lèi)和屬性C++/CLI中可以定義兩種結(jié)構(gòu)或類(lèi)類(lèi)型,一種為數(shù)值類(lèi)類(lèi)型(ValueClassType)和數(shù)值結(jié)構(gòu)類(lèi)型(ValueStructType);另一種是引用類(lèi)類(lèi)型(RefClassType)和引用結(jié)構(gòu)類(lèi)型(RefStructType)。與本地C++一樣,結(jié)構(gòu)類(lèi)型與類(lèi)類(lèi)型的區(qū)別在于struct類(lèi)型的缺省訪問(wèn)控制是公有的,而class類(lèi)型的缺省訪問(wèn)控制是私有的。本節(jié)主要討論數(shù)值類(lèi)和引用類(lèi)。雙字關(guān)鍵字valueclass用于聲明數(shù)值類(lèi)類(lèi)型,refclass用于聲明引用類(lèi)類(lèi)型。數(shù)值類(lèi)類(lèi)型定義的對(duì)象可以分配在堆棧、本地堆或托管堆中,引用類(lèi)聲明的對(duì)象只能在托管堆中分配空間。11.5C++/CLI中的類(lèi)和屬性引用類(lèi)的定義方式與本地C++類(lèi)基本相同,例如: refclassBox{ public: Box(); ... private: doublelength; doublewidth; doubleheight; };C++/CLI的類(lèi)比本地C++中的類(lèi)增加了屬性成員,語(yǔ)法上用property關(guān)鍵字聲明類(lèi)的屬性。例如propertydoublevalue。屬性的引入省略了本地C++類(lèi)中為存取私有數(shù)據(jù)成員編寫(xiě)類(lèi)似set或get的成員函數(shù)。屬性提供了更方便、更清晰的語(yǔ)法來(lái)訪問(wèn)或修改類(lèi)的數(shù)據(jù)成員。11.5C++/CLI中的類(lèi)和屬性在用法上,類(lèi)中的屬性與成員變量比較相似,其實(shí)它們有質(zhì)的區(qū)別,主要區(qū)別在于:變量名引用了某個(gè)存儲(chǔ)單元,而屬性名則是調(diào)用某個(gè)函數(shù)。屬性擁有訪問(wèn)屬性的set()和get()函數(shù),并且函數(shù)名必須是get或set。當(dāng)使用屬性名進(jìn)行讀取或賦值時(shí),實(shí)際上在調(diào)用該函數(shù)的get()或set()函數(shù)。如果一個(gè)屬性?xún)H提供了get()函數(shù),則它是只讀屬性;如果一個(gè)屬性?xún)H提供set()函數(shù),則它是只寫(xiě)屬性。C++/CLI的類(lèi)可以有兩種不同的屬性:標(biāo)量屬性(ScalarProperties)和索引屬性(IndexProperties)。標(biāo)量屬性是指通過(guò)屬性名來(lái)訪問(wèn)的單值;索引屬性是利用屬性名加方括號(hào)來(lái)訪問(wèn)的一組值。例如String類(lèi),其Length屬性為標(biāo)量屬性,用object->Length來(lái)訪問(wèn)其長(zhǎng)度,且Length是個(gè)只讀屬性。String還包含了索引屬性,可以用object[idx]來(lái)訪問(wèn)字符串中第idx個(gè)字符。11.5C++/CLI中的類(lèi)和屬性屬性可以與類(lèi)的實(shí)例(類(lèi)對(duì)象)相關(guān),此時(shí)屬性被稱(chēng)為實(shí)例屬性(InstanceProperties),如String類(lèi)的Length屬性;如果用static修飾符指定屬性,則屬性為類(lèi)屬性,類(lèi)的所有對(duì)象在該屬性項(xiàng)上都具有相同的屬性值?!纠?1-5】設(shè)計(jì)人民幣數(shù)值類(lèi)和商品引用類(lèi),在類(lèi)中應(yīng)用屬性訪問(wèn)私有數(shù)據(jù)成員。11.5C++/CLI中的類(lèi)和屬性程序說(shuō)明:(1) 數(shù)值類(lèi)RMB對(duì)象可以存儲(chǔ)在堆棧、本地堆和托管堆上,而引用類(lèi)Goods的對(duì)象只能存儲(chǔ)在托管堆上。RMBmyRMB定義的對(duì)象保存在堆棧上,Goodscomputer(...)所定義的對(duì)象保存在托管堆中,computer僅保存了它的引用地址。語(yǔ)句Goods^gHandle=gcnewGoods(...)能正確運(yùn)行,而語(yǔ)句Goods*goodsPtr=newGoods(...)將導(dǎo)致編譯錯(cuò)誤。valueclass類(lèi)是System::ValueType的派生類(lèi),refclass類(lèi)是繼承于System::Object的。(2) C++/CLI中的函數(shù)不能有默認(rèn)參數(shù)。若為RMB類(lèi)的構(gòu)造函數(shù)指定默認(rèn)參數(shù),例如語(yǔ)句RMB(inty,intj,intf=0),在程序編譯時(shí)報(bào)告錯(cuò)誤信息如下:無(wú)法為托管類(lèi)型或泛型函數(shù)的成員函數(shù)聲明默認(rèn)參數(shù)。11.5C++/CLI中的類(lèi)和屬性(3) 語(yǔ)句myRMB.value=2345.56;是通過(guò)屬性設(shè)置類(lèi)中私有數(shù)據(jù),computer.Name是讀取屬性Name中的值,computer.Price是讀取Goods類(lèi)對(duì)象中私有數(shù)據(jù)price的值。Goods類(lèi)中定義了屬性Name和Price。Name屬性沒(méi)有定義set和get,也沒(méi)有與之對(duì)應(yīng)的私有數(shù)據(jù)成員name。Price屬性只定義get函數(shù),沒(méi)有定義set函數(shù),為只讀屬性。下面為屬性賦值的語(yǔ)句第一條能正常運(yùn)行,第二條在編譯時(shí)報(bào)錯(cuò):computer.Name="Dellvostro3700"; //正確computer.Price=8908.90;//錯(cuò)誤!因?yàn)镚oods::Price沒(méi)有定義set

以跟蹤方式運(yùn)行程序,觀察computer對(duì)象,可見(jiàn)該對(duì)象中多了一個(gè)由系統(tǒng)為其添加的成員變量<backing_store>Name,其中保存了Name屬性值:“聯(lián)想V470G-ISE”。11.6C++/CLI中的多態(tài)與接口C++/CLI中的多態(tài)采用了與本地C++相同的實(shí)現(xiàn)方式。在語(yǔ)法上,C++/CLI要求顯式地聲明虛函數(shù)和抽象類(lèi)。C++/CLI中的虛函數(shù)要求在派生類(lèi)中用virtual關(guān)鍵字顯式地聲明,并用override關(guān)鍵字聲明為重載函數(shù)。下面的代碼段說(shuō)明了虛函數(shù)的聲明方法。Shape類(lèi)為基類(lèi),Circle類(lèi)為派生類(lèi),其中虛函數(shù)draw為重載函數(shù): refclassShape{ public: virtualvoiddraw(); }; refclassCircle:Shape{ public: virtualvoiddraw()override; }11.6C++/CLI中的多態(tài)與接口派生類(lèi)的函數(shù)還可以用new關(guān)鍵字指明沒(méi)有重寫(xiě)這個(gè)函數(shù)的基類(lèi)版本,它隱藏了基類(lèi)的相同函數(shù)。例如,Circle類(lèi)中的draw函數(shù)聲明為new: virtualvoiddraw()new;此時(shí),下面的語(yǔ)句所調(diào)用的draw函數(shù)將來(lái)自不同的類(lèi): Shape^shandle=gcnewCircle(); shandle->draw(); //調(diào)用Shape的draw函數(shù) CirclecircleObj; circleObj.draw(); //調(diào)用Circle的draw函數(shù)這里的new關(guān)鍵字是上下文敏感的,只在托管類(lèi)型的函數(shù)聲明中才充當(dāng)該角色。關(guān)鍵字sealed用于指明類(lèi)或函數(shù)不能被重寫(xiě)。Shape中的draw函數(shù)如果聲明為voiddraw()sealed;,則任何派生類(lèi)都不允許重寫(xiě)draw函數(shù)。如果以refclassShapesealed{};方式聲明Shape類(lèi),則Shape類(lèi)不能作為基類(lèi),其所有成員函數(shù)都被隱式地聲明為sealed函數(shù)。11.6C++/CLI中的多態(tài)與接口抽象類(lèi)在本地C++中是指含有純虛函數(shù)的類(lèi),純虛函數(shù)的聲明是在后面添加“=0”。在C++/CLI中依然使用這種風(fēng)格的聲明,同時(shí)又添加了一個(gè)關(guān)鍵字abstract作為替代方案。下面的純虛函數(shù)聲明在C++/CLI中是等價(jià)的: virtualvoiddraw()abstract; virtualvoiddraw()=0;程序員可以用abstract關(guān)鍵字聲明類(lèi)的抽象類(lèi),例如refclassShapeabstract{...};。聲明為abstract的托管類(lèi)并不會(huì)隱式地將類(lèi)中的任何函數(shù)聲明為abstract。與本地C++不同,托管的抽象類(lèi)并不一定要包含純虛函數(shù),可以為抽象類(lèi)中的每個(gè)函數(shù)定義一個(gè)實(shí)現(xiàn),供所有派生類(lèi)使用。抽象類(lèi)中的純虛函數(shù)必須用abstract或“=0”進(jìn)行聲明。11.6C++/CLI中的多態(tài)與接口C++/CLI還支持名字重寫(xiě)。該技巧允許派生類(lèi)重寫(xiě)它繼承的虛函數(shù),并為這個(gè)函數(shù)提供一個(gè)新的名稱(chēng)。例如,在Circle類(lèi)中可以用一個(gè)新的函數(shù)display對(duì)draw函數(shù)進(jìn)行重寫(xiě): refclassCircle:Shape{ public: virtualvoiddisplay()=Shape::draw; };使用名字重寫(xiě)技巧對(duì)類(lèi)層次結(jié)構(gòu)高層的多個(gè)函數(shù)進(jìn)行重寫(xiě),在復(fù)雜的類(lèi)層次結(jié)構(gòu)中有時(shí)使用這個(gè)技巧會(huì)帶來(lái)方便。11.6C++/CLI中的多態(tài)與接口接口(interface)是C++/CLI新引入的概念。雖然接口的定義方式與托管類(lèi)的定義比較相似,但兩者完全不同。接口本質(zhì)上是一種類(lèi),其中聲明了一組由其他類(lèi)來(lái)實(shí)現(xiàn)的函數(shù),數(shù)值類(lèi)和引用類(lèi)都能實(shí)現(xiàn)接口中的函數(shù)。接口不實(shí)現(xiàn)它的函數(shù)成員,而是在繼承于該接口的派生類(lèi)中定義它們。關(guān)鍵字interfaceclass用于聲明接口,無(wú)需聲明,接口中的函數(shù)均是純虛函數(shù)。接口聲明方式如下,通常接口名用大寫(xiě)字母I開(kāi)頭: interfaceclassIMyInterface{ voidTest(); voidShow(); };11.6C++/CLI中的多態(tài)與接口C++/CLI不同于本地C++,類(lèi)的繼承只支持單繼承,并不支持類(lèi)的多重繼承,而接口支持多重繼承,因此一個(gè)類(lèi)可通過(guò)繼承多個(gè)接口,實(shí)現(xiàn)與多重繼承相似的功能。接口中含有函數(shù)、事件和屬性的聲明,并且它們的訪問(wèn)權(quán)限均為公有的。接口中還可以有靜態(tài)成員(數(shù)據(jù)成員、函數(shù)、事件和屬性),這些靜態(tài)成員必須在接口中定義。【例11-6】接口及其實(shí)現(xiàn)示例。11.6C++/CLI中的多態(tài)與接口程序說(shuō)明:(1)接口中的函數(shù)默認(rèn)為純虛函數(shù),IShape和IContainer中的函數(shù)均沒(méi)有顯式地聲明為virtual,但在實(shí)現(xiàn)接口函數(shù)的Circle、Rectangle和Cuboid類(lèi)中需要顯式地聲明為虛函數(shù)。IShape中聲明了Area屬性,接口中還可以聲明事件。Cuboid類(lèi)實(shí)現(xiàn)了IShape和IContainer接口。引用類(lèi)可以在繼承另一個(gè)類(lèi)的同時(shí)實(shí)現(xiàn)多個(gè)接口。11.6C++/CLI中的多態(tài)與接口例如,在本例程中可添加圓柱類(lèi)如下:refclassCylinder:publicCircle,IShape,IContainer{public: Cylinder(doubleh,doubler):hight(h),Circle(r){} propertydoubleArea{ virtualdoubleget()new{ return2*Circle::Area+hight*2*PI*Radius; } } virtualvoidShowMSG()override{ Console::WriteLine(L"圓柱體的底面半徑為:{0},高為{1},表面積為:{2},體積為:{3}",Radius,hight,Area,Volume()); } virtualdoubleVolume(){ returnCircle::Area*hight; }private: doublehight;};11.7C++/CLI中的模板和泛型在C++/CLI中,可以如同本地C++一樣創(chuàng)建并使用托管類(lèi)模板和函數(shù)模板。例如,棧類(lèi)在托管代碼中可如下聲明: template<typenameT> refclassManagedStack{ ... }; 托管類(lèi)模板完全支持本地類(lèi)模板的所有特性,如非模板參數(shù)和顯式實(shí)例化。與托管類(lèi)一樣,托管類(lèi)模板也不能聲明其他類(lèi)或函數(shù)作為自己的友元,但可以被聲明為本地類(lèi)的友元。11.7C++/CLI中的模板和泛型在C++/CLI中,提供了一種與本地C++模板非常相似的代碼復(fù)用技術(shù),稱(chēng)為泛型(Generic)。C++/CLI中不僅能定義泛型數(shù)值類(lèi)、泛型引用類(lèi)和泛型函數(shù),還能聲明泛型接口類(lèi)和泛型委托。聲明泛型類(lèi)的語(yǔ)法類(lèi)似于托管類(lèi)模板,關(guān)鍵字template用關(guān)鍵字generic替換。例如:generic<typenameT>refclassStack{...};泛型是由公共語(yǔ)言運(yùn)行時(shí)(CLR)定義的,具有跨程序集的能力,泛型類(lèi)和泛型函數(shù)可被其他.NET語(yǔ)言(如C#)所編寫(xiě)的代碼使用。11.7C++/CLI中的模板和泛型泛型與模板有許多相似之處,但它們實(shí)際上存在質(zhì)的區(qū)別。主要區(qū)別如下:泛型是在運(yùn)行時(shí)實(shí)例化,而模板是在編譯時(shí)實(shí)例化。泛型類(lèi)型無(wú)法作為模板類(lèi)型參數(shù),而模板類(lèi)型可以作為泛型類(lèi)型參數(shù)。泛型使用類(lèi)型約束限制在泛型代碼中可以使用的類(lèi)型。泛型類(lèi)型參數(shù)必須是引用類(lèi)型的句柄、接口類(lèi)型句柄或值類(lèi)型,不支持非類(lèi)型參數(shù)或默認(rèn)值。11.7C++/CLI中的模板和泛型C++/CLI提供了幾種類(lèi)型約束。類(lèi)約束表示類(lèi)型實(shí)參必須是一個(gè)特定基類(lèi)或其子類(lèi)的對(duì)象。接口約束表示類(lèi)型實(shí)參必須已實(shí)現(xiàn)某特定的接口。下面的代碼聲明了一個(gè)含有約束限制的泛型函數(shù): generic<typenameT>whereT:IComparable TMaxElement(array<T>^x){ Tmax(x[0]); for(inti=1;i<x->Length;i++) if(max->CompareTo(x[i])<0) max=x[i]; returnmax; }11.7C++/CLI中的模板和泛型generic<typenameT>后面的whereT:IComparable是類(lèi)型約束,指明T必須實(shí)現(xiàn)接口IComparable。實(shí)現(xiàn)了IComparable接口的類(lèi)型必須定義一個(gè)CompareTo成員函數(shù),對(duì)同種類(lèi)型的對(duì)象進(jìn)行比較。泛型函數(shù)MaxElement中使用該函數(shù)來(lái)判定數(shù)組中第i個(gè)單元的元素是否大于max。如果在泛型聲明時(shí)沒(méi)有指定類(lèi)型約束,默認(rèn)的約束是Object。泛型的一個(gè)類(lèi)型參數(shù)可以應(yīng)用多個(gè)約束,方法是在where分句中用逗號(hào)分隔多個(gè)約束形成約束列表?!纠?1-7】使用泛型技術(shù)設(shè)計(jì)鏈棧,并測(cè)試。

11.8C++/CLI中的異常C++/CLI中的異常與本地C++異常處理十分相似。在托管代碼中,System::Exception類(lèi)是所有異常類(lèi)的基類(lèi),系統(tǒng)只捕獲并處理由Exception類(lèi)及其子類(lèi)拋出的異常?;?lèi)Exception派生了兩個(gè)重要的異常類(lèi):SystemException類(lèi)和ApplicationException類(lèi)。SystemException的派生類(lèi)預(yù)定義了公共語(yǔ)言運(yùn)行時(shí)異常類(lèi),例如:數(shù)組越界訪問(wèn)CLR拋出IndexOutOfRangeException類(lèi),引用不存在的對(duì)象時(shí)CLR拋出NullReferenceException異常類(lèi)。ApplicationException類(lèi)是程序發(fā)生非致命應(yīng)用程序錯(cuò)誤時(shí)引發(fā)的異常類(lèi),系統(tǒng)用它區(qū)分應(yīng)用程序定義的異常與系統(tǒng)定義的異常。用戶(hù)應(yīng)用程序可定義并引發(fā)從ApplicationException類(lèi)派生的自定義異常類(lèi)。11.8C++/CLI中的異常Exception異常類(lèi)包含很多屬性,可以幫助標(biāo)識(shí)異常的代碼位置、類(lèi)型、幫助文件和原因。Exception中的屬性有StackTrace、InnerException、Message、HelpLink、HResult、Source、TargetSite和Data等。Message屬性存儲(chǔ)了當(dāng)前異常的錯(cuò)誤消息。StackTrace屬性返回源于異常引發(fā)位置的調(diào)用堆棧的框架。當(dāng)兩個(gè)或多個(gè)異常之間存在因果關(guān)系時(shí),InnerException屬性會(huì)維護(hù)此信息。關(guān)于異常的補(bǔ)充信息可以存儲(chǔ)在Data屬性中。try-catch格式語(yǔ)句在C++/CLI中依然有效,此外,C++/CLI還引入了新關(guān)鍵字finally,支持try-finally和try-catch-finally兩種格式的語(yǔ)句。11.8C++/CLI中的異常try-catch-finally語(yǔ)句是在try-catch語(yǔ)句后加上finally代碼段,其中catch語(yǔ)句同樣可以有多個(gè),但finally語(yǔ)句只能有一個(gè)并且在所有catch語(yǔ)句之后。try語(yǔ)句拋出的異常依然由不同的catch語(yǔ)句捕獲并處理。無(wú)論異常是否發(fā)生,finally語(yǔ)句中的代碼段總是被執(zhí)行。finally代碼段中通常是程序必須執(zhí)行的任務(wù),如資源釋放、關(guān)閉文件等。finally語(yǔ)句的優(yōu)先級(jí)較高,即使之前的try或catch語(yǔ)句的代碼段中使用了break、continue等跳轉(zhuǎn)語(yǔ)句,finally代碼段都要被執(zhí)行。此外,finally代碼段中不能使用return語(yǔ)句,break和continue語(yǔ)句也只能在代碼段中跳轉(zhuǎn),否則編譯器將報(bào)告錯(cuò)誤。C++/CLI的異常機(jī)制也是使用throw拋出異常。與本地C++不同,C++/CLI的throw語(yǔ)句只能拋出Exception及其派生類(lèi)對(duì)象的引用。除此限制之外,用法與本地C++拋出異常的方法相似。下面的語(yǔ)句給出了一個(gè)典型的異常拋出方法:throwgcnewException("error!");11.8C++/CLI中的異常【例11-8】try-catch-finally語(yǔ)句應(yīng)用示例。

程序說(shuō)明:(1) 語(yǔ)句x=int::Parse(Console::ReadLine());中的int::Parse函數(shù)是將從鍵盤(pán)輸入的數(shù)值內(nèi)容的字符串轉(zhuǎn)換為int類(lèi)型整數(shù)。如果字符串內(nèi)容為空,則拋出ArgumentNullException異常。如果字符串內(nèi)容不是數(shù)值,則拋出FormatException異常。如果字符串內(nèi)容超出int類(lèi)型所能表示的值區(qū)間,則拋出OverflowException異常。(2) 異常處理在提高程序容錯(cuò)能力的同時(shí),也會(huì)造成程序的性能、可讀性和可維護(hù)性的下降。通常在程序的高層次處理異常,在編寫(xiě)底層方法、模塊或組件時(shí),盡量少用或者不用異常處理,而是在調(diào)用它們的代碼中執(zhí)行異常處理。11.9C++/CLI中的枚舉C++/CLI的托管枚舉類(lèi)型與本地C++在聲明和訪問(wèn)方式上有一些不同。用關(guān)鍵字enumclass聲明托管枚舉類(lèi)型。例如:enumclassWeek{Mon=1,Tues,Wed,Thurs,Fri,Sat,Sun}枚舉類(lèi)型中的枚舉常量是對(duì)象,不再是本地C++中使用的整數(shù)值。雖然在默認(rèn)情況下,枚舉常量是Int32值類(lèi)型的對(duì)象,但C++/CLI不允許直接將枚舉常量與整數(shù)或其他簡(jiǎn)單類(lèi)型進(jìn)行算術(shù)運(yùn)算,除非用safe_cast顯式地轉(zhuǎn)換為整數(shù)。在聲明枚舉類(lèi)型時(shí),允許修改枚舉常量所封裝的數(shù)據(jù)類(lèi)型。下面語(yǔ)句用char類(lèi)型替換了默認(rèn)的Int32類(lèi)型,方法是在枚舉類(lèi)型名的后面加注“:char”:enumclassSuit:char{Clubs='C',Diamonds='D',Hearts='H',Spades='S'};11.9C++/CLI中的枚舉不同于本地C++,托管枚舉變量的賦值需要在枚舉常量的前面加上枚舉名和作用域解析運(yùn)算符。例如:Weektoday=Week::Fri; //Weektoday=Fri;為錯(cuò)誤!可以用“++”和“--”運(yùn)算符對(duì)枚舉變量進(jìn)行增加或減?。簍oady++; //today中內(nèi)容為Week::Sat用關(guān)系運(yùn)算符(==、!=、<、<=、>、>=)可以對(duì)枚舉變量進(jìn)行邏輯運(yùn)算:today==Week::Mon //若today中值為Week::Mon表達(dá)式值為真,否則為假

枚舉的一個(gè)重要用途是設(shè)置標(biāo)志位,稱(chēng)為標(biāo)志枚舉。托管枚舉變量同樣能用于程序運(yùn)行時(shí)狀態(tài)的標(biāo)志。與本地C++相同,用&、|和~運(yùn)算符也可以對(duì)標(biāo)志位進(jìn)行設(shè)置或清除。11.9C++/CLI中的枚舉下面的代碼段給出了標(biāo)志枚舉類(lèi)型的定義、位設(shè)置、位清除及標(biāo)志位判別的方法:enumclassWindowStyle{ //窗口狀態(tài)枚舉類(lèi)型

MINIMUM_BUTTON=1, //十六進(jìn)制表示為0x0001MAXIMUM_BUTTON=2,CLOSE_BUTTON=4 }//ws變量記錄窗口狀態(tài),窗口既有MINIMUM_BUTTON又有CLOSE_BUTTON按鈕WindowStylews=WindowStyle::MINIMUM_BUTTON|WindowStyle::CLOSE_BUTTON;//窗口關(guān)閉MINIMUM_BUTTON按鈕,清除MINIMUM_BUTTON標(biāo)志位ws=ws&~WindowStyle::MINIMUM_BUTTON//判別窗口是否有CLOSE_BUTTON按鈕(ws&WindowStyle::CLOSE_BUTTON)==WindowStyle::CLOSE_BUTTON11.9C++/CLI中的枚舉【例11-9】枚舉類(lèi)型變量應(yīng)用示例。程序說(shuō)明:(1) 枚舉類(lèi)型Suit在聲明時(shí)為每個(gè)枚舉常量指定了一個(gè)字符值。程序運(yùn)行結(jié)果的第一行輸出的整型值為67,它是字母C的ASCII碼值。(2) 枚舉類(lèi)型FlagBits聲明語(yǔ)句前的[Flags]是用于告知編譯器枚舉常量是簡(jiǎn)單的位值。去除該項(xiàng),程序運(yùn)行結(jié)果的第2行將輸出:枚舉變量flags的值:5,轉(zhuǎn)換為int類(lèi)型的值:511.10.NET中的委托與事件11.10.1委托委托(delegate)是一種托管對(duì)象,其中封裝了對(duì)一個(gè)或多個(gè)函數(shù)的類(lèi)型安全的引用。委托是基于面向?qū)ο蟮姆庋b思想,將一個(gè)或多個(gè)指向函數(shù)的指針?lè)庋b在對(duì)象中。委托的功能在某些方面類(lèi)似于本地C++的函數(shù)指針,但委托是面向?qū)ο蟮?,并且是?lèi)型安全的。委托的聲明使用關(guān)鍵字delegate外加函數(shù)原型的方式,例如:publicdelegatevoidFunDelegate(int);//FunDelegate為委托類(lèi)型每個(gè)委托實(shí)際上都是一個(gè)獨(dú)立的類(lèi),它們派生于System::MultiCastDelegate類(lèi),而后者又是派生于System::Delegate類(lèi)。所有委托最終都繼承了System::Delegate類(lèi)的成員函數(shù),這些成員函數(shù)中有一個(gè)Invoke函數(shù),該函數(shù)的返回類(lèi)型和參數(shù)與委托所聲明的函數(shù)相同。11.10.NET中的委托與事件與引用類(lèi)相似,委托的使用也需要定義一個(gè)委托對(duì)象,并且也是用gcnew生成一個(gè)托管對(duì)象。委托對(duì)象定義方式如下:FunDelegate^funHandler=gcnewFunDelegate(myClass::staticMbeFun);//定義委托這里,funHandler為委托句柄,引用了托管堆中的一個(gè)委托對(duì)象。委托封裝了myClass類(lèi)的靜態(tài)成員函數(shù)staticMbeFun,并且該函數(shù)的形參和返回類(lèi)型與委托聲明中的函數(shù)原型相一致。對(duì)于類(lèi)的非靜態(tài)成員函數(shù),在定義委托時(shí)需要調(diào)用委托的雙參構(gòu)造函數(shù),并傳遞預(yù)先已定義的類(lèi)對(duì)象和類(lèi)的成員函數(shù)。方法如下:myClass^Obj=gcnewmyClass; //定義托管對(duì)象FunDelegate^funHandler=gcnewFunDelegate(Obj,&myClass::mbFun);11.10.NET中的委托與事件其中,mbFun為myClass類(lèi)的成員函數(shù),并且與委托聲明中的函數(shù)原型匹配。本地C++的函數(shù)指針一次只能指向一個(gè)函數(shù),而委托不受這種限制。MultiCastDelegate類(lèi)通過(guò)存儲(chǔ)一個(gè)委托實(shí)例的鏈表(稱(chēng)為委托的調(diào)用列表),允許一個(gè)委托同時(shí)封裝多個(gè)函數(shù)。向調(diào)用列表添加委托實(shí)例的方法是使用已經(jīng)重載的+=運(yùn)算符,從調(diào)用列表刪除委托實(shí)例的方法是使用重載的-=運(yùn)算符。例如:funHandler+=gcnewFunDelegate(othObj,&OtherClass::fun); //添加委托實(shí)例funHandler-=gcnewFunDelegate(Obj,&myClass::mbFun); //刪除委托實(shí)例11.10.NET中的委托與事件通過(guò)委托對(duì)象可以方便地調(diào)用封裝于委托調(diào)用列表中的函數(shù),調(diào)用方法有兩種:一種是直接通過(guò)委托句柄調(diào)用,另一種是調(diào)用Invoke函數(shù)。例如:funHandler(100); //通過(guò)委托句柄調(diào)用funHandler->Invoke(200); //通過(guò)Invoke函數(shù)調(diào)用在一次委托調(diào)用過(guò)程中,委托調(diào)用列表中所指向的函數(shù)均被調(diào)用執(zhí)行。從功能上,委托似乎只是一種間接地調(diào)用函數(shù)的方法。實(shí)事上,委托在許多場(chǎng)合是十分有用的,委托既可以作為參數(shù)傳遞給函數(shù),也可以用于將函數(shù)從一個(gè)類(lèi)傳遞給另一個(gè)類(lèi)。委托是一個(gè)定義了方法的類(lèi)類(lèi)型,利用它可以將方法當(dāng)作另一個(gè)方法的參數(shù)來(lái)進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用分支語(yǔ)句,同時(shí)使得程序具有更好的可擴(kuò)展性。11.10.NET中的委托與事件【例11-10】委托聲明、定義與調(diào)用方法示例。程序說(shuō)明:(1) 程序中定義了一個(gè)sumDelegate委托類(lèi)型,用其定義了托管委托

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論