情有獨鍾C++:Visual C++ .NET編譯器的新特性(轉)

post0發表於2007-08-11
情有獨鍾C++:Visual C++ .NET編譯器的新特性(轉)[@more@]

摘要

老資格的 C++ 程式設計師們都想知道:他們賴以生存的 C++ 語言在 C# 和微軟的 .NET 的衝擊下何去何從?本文將對 .NET 世界中的 C++ 進行簡要描述。在 .NET 中,C++ 分裂為兩大陣營:受管程式碼 (Managed Code) 和非受管程式碼 (Unmanaged Code)。非受管程式碼不使用通用語言執行時環境 (CLR) ,而受管程式碼則用到了 Managed Extensions for C++ 。本文將對兩者分別討論。

C++ 社群給人的感覺就象一個大家庭:初生的小寶寶總是倍受呵護,而年長的孩子卻是無人關心。如此被忽視,又怎能教人不心痛?事實上,技術領域的情況比這更糟:技術的革新實在太快,人們疲於奔命卻無可奈何,否則連飯碗都保不住了。

如今,微軟公司的新產品 .NET 框架被炒得沸沸揚揚——的確很不錯;眾人還對所謂的 C# 語言連聲喝彩。作為 C++ 的程式設計師,心裡卻很不是滋味:我是不是也要改行學 C# 了?因為人們只有在比較 C# 與 C++ 才會偶爾提及 C++ 了。

C++ 程式設計師要過時了嗎?絕不!本文先簡要描述 Visual Studio .NET 為 C++ 引入的新特性,然後再介紹微軟公司對新版 C++ 的計劃。首先從兩個方面來談談 Visual Studio .NET 裡的 C++ :標準的 C++ 和 Managed Extensions for C++ 。

對標準 C++ 的擴充主要是為了保持相容性;也就是說,為了保持國際標準化組織 (ISO) 所規定的 C++ 語言特性。而 Managed Extensions for C++ 則是為了把 C++ 納入 .NET 框架之中。

Visual Studio .NET 下的標準 C++

為了保持對 ISO 標準的相容性,標準 C++ 作了如下改進:

(1) 虛擬函式的返回值現在支援共變 (covariant) 型別了,這是類層次體系上的一個重大改進;

(2) 支援對靜態整數型別常量( static const integer )成員的顯式初始化;

(3) 主函式的返回值預設為 0 。

現在我來逐一介紹它們。

第一項是增加 covariant 返回型別,它已經由標準委員會核准。也就是說,如果基類的某個虛擬函式返回值是該類本身的例項,那麼它在派生類中被過載後也能返回此派生類本身的例項。在類層次體系中,這是一種很重要的設計模式;在 Visual Studio .NET 中,它也大受歡迎。

例如,對於抽象基類 Query :

class Query {

public:

virtual Query *clone() = 0;

// ...

};

如果想要其派生類例項 NotQuery 的 clone 函式返回一個 NotQuery 物件,即:

class NotQuery {

public:

virtual Query *clone()

{ return new NotQuery( this ); }

// ...

public:

Query *operand;

};

當沒有 covariant 返回型別支援時,clone 的返回型別必然是 Query* :

// without covariant return type support

virtual Query* clone()

{ return new NotQuery(

this ); }

此時如果把 clone 的返回值分配給 Query* 型別的指標,那麼一切工作正常:

NotQuery::NotQuery( const NotQuery &rhs )

{ operand = rhs.operand->clone(); }

但是如果要分配給 NotQuery* 型別的指標呢?

NotQuery nq( new NameQuery( "Shakespeare" );

這樣就不行了:

// oops: illegal assignment ...

NotQuery *pnq0 = nq->clone();

只能這樣:

// ok: required explicit cast ...

NotQuery *pnq1 =

static_cast(nq->clone());

現在有了 covariant 返回型別,你就可以顯式返回 NotQuery* 型別了:

// with covariant return type support

virtual NotQuery* clone()

{ return new NotQuery( this ); }

於是,clone 的返回型別變得更直觀,不再需要強制型別轉換了:

這樣是對的:

// ok: implicit conversion ... ;

Query *pq = nq->clone();

這樣也沒問題:

// ok: no conversion necessary ... ;

NotQuery *pnq = nq->clone();

第二項是靜態整數常量型別成員的顯式初始化,它對 C++ 的影響就沒有 covariant 返回型別那麼大了。它僅僅給使用常量表示式(如:定長陣列)的類的設計帶來了方便。例如:

class Buffer {

static const int ms_buf_size = 1024;

char m_buffer[ ms_buf_size ];

};

static const int 型別成員被初始化以後,就可以為本類的其它成員所用,例如設定 m_buffer 的大小,而不用象以前那樣,使用列舉變數了。

第三項是主函式的預設返回值為 0 。主函式的返回值代表程式的退出狀態。習慣上,返回 0 代表程式正常結束。在標準 C++ 裡,如果沒有顯性指定返回值,編譯器就會自動地在主函式末尾插入一行:

return 0;

進入 Visual Studio .NET 時代,Visual C++ 終於支援它了!

Visual Studio .NET 下的受管 C++

Visual Studio .NET 的 Managed Extensions for C++ 提供了三種基本的應用策略:

(1) 為原有的 API 提供 .NET“包裝”,把 C++ 類統統移植到 .NET 平臺中。

(2) 混用 C++ 類與微軟 .NET 的三種框架類:

核心語言支援,例如:收集類和系統輸入/輸出;

基礎程式類, 例如:執行緒支援,網路套接字和正規表示式;

應用領域支援,例如:XML、ASP.NET、Web 服務、Windows 窗體、ADO.NET,等等。

(3) 象 C# 和 Visual Basic 那樣直接操作 .NET 環境。然而,目前尚無相應的快速開發工具(RAD)用於 Windows 窗體和 Web 表單的視覺化程式設計。

先來看看第一種方案:用 .NET 包裝原有的程式碼。在我的 C++ Primer 一書 (Addison-Wesley,1998) 中,我示範了一個相當大的文字查詢系統,其中大量使用了 STL 容器類用於解析文字檔案和建立資料結構。它的引用檔案內容如下:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

建立的資料結構如下:

typedef pair location;

typedef vector loc;

typedef vector text;

typedef pair text_loc;

class TextQuery {

public:

// ...

private:

vector *lines_of_text;

text_loc *text_locations;

map *word_map;

Query *query;

static string filt_elems;

vector line_cnt;

};

Query 類是用於解釋查詢語言的抽象基類,下面演示了它的功能:

Enter a query-please separate each item by a space.

Terminate query (or session) with a dot( . ).

==> fiery && ( bird || shyly )

fiery ( 1 ) lines match

bird ( 1 ) lines match

shyly ( 1 ) lines match

( bird || shyly ) ( 2 ) lines match

fiery && ( bird || shyly ) ( 1 ) lines match

Requested query: fiery && ( bird || shyly )

(3) like a fiery bird in flight. A beautiful fiery bird, he tells her,

主程式程式碼如下:

int main()

{

TextQuery tq;

tq.build_up_text();

tq.query_text();

}

現在我把 TextQuery 介面提交給 .NET 平臺,沒有修改程式碼,更沒有重寫函式。最終,一切順利。假如移植到 .NET 平臺必須完全重寫程式碼的話,我可能就不會那麼做了。幸好受管 C++ 提供了包裝移植的方式。下面是包裝的一種方式:

#include "TextQuery.h"

__gc class TextQueryNet

{

private:

TextQuery *pquery;

public:

TextQueryNet() : pquery( new TextQuery()){}

~TextQueryNet(){ delete pquery; }

void query_text() { pquery->query_text(); }

void build_up_text() { pquery->build_up_text();}

// ...

};

關鍵字 __gc 用於指定受管類,它們接受垃圾回收器管理,佔用通用語言執行時 (CLR) 受管堆。與原先的程式碼一樣,我把原生類 (native class) 宣告為指標型別成員,使用關鍵字 new 在非受管堆分配空間,由於它不支援垃圾回收管理,故在解構函式中使用 delete 回收空間。build_up_text 和 query_text 都是殘餘 (stub) 函式,用於呼叫真正的 TextQuery 物件。

作為對照,我們來看看由 Managed C++ Project Wizard 自動生成的主函式:

#include "stdafx.h"

#using

#include

using namespace System;

#include "gc_TextQuery.h"

int _tmain(void)

{

Console::WriteLine(

S"Beginning managed wrapper test ..." );

TextQueryNet *tqn = new TextQueryNet();

tqn->build_up_text();

tqn->query_text();

Console::WriteLine(

S"Ending managed wrapper test ..." );

return 0;

}

現在,我們來討論 .NET 框架的利用。如果有人問我,ISO 標準 C++ 最大的缺點是什麼?我的答案是:它沒有提供支援諸如執行緒、網路程式設計、正規表示式以及XML 等應用領域的標準庫。標準委員會已將其列入下一輪工作計劃,但那是一年以後的事了。目前我們怎麼辦?其實,.NET 框架已經提供了引人入勝的解決方案。下面演示一個簡單的 Socket 伺服器類,它利用了 .NET 框架:

// include the necessary assemblies

#using

#using

#using

#using

// open up the associated namespaces

using namespace System;

using namespace System::Threading;

using namespace System::Data;

using namespace System::Data::SqlClient;

using namespace System::Collections;

using namespace System::Net::Sockets;

// ok: here is our class

__gc class SocketDemo_Server

{

private:

static const int port = 4554;

static const int maxPacket = 128;

TcpListener *tcpl;

DataSet *ds;

DataRowCollection *rows;

public:

SocketDemo_Server();

void Start();

void handleConnection();

// grab the data from the SQL database

void retrieveData();

};

它的功能是查詢 Northwind 公司職員的電話號碼;其中的 SQL 資料庫可以在 Visual Studio .NET 發行版本中找到。

再來看看它在執行過程中對三位客戶的處理記錄:

Server[4554]: OK: started TcpListener ...

Server[4554]: OK: listening for connections ...

Server[4554]: OK: retrieved SQL database info ...

Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Fuller

Server[4554]: OK: first request for Fuller

Server[4554]: Phone number for Fuller: (206) 555-9482

Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for King

Server[4554]: OK: first request for King

Server[4554]: Phone number for King: (71) 555-5598

Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Fuller

Server[4554]: OK: cached request for Fuller

Server[4554]: Phone number for Fuller: (206) 555-9482

Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Musil

Server[4554]: OK: first request for Musil

Server[4554]: Phone number for Musil: Sorry. Cannot be found.

下面是 Start 函式的實現程式碼:

void SocketDemo_Server::

Start()

{

try

{

tcpl = new TcpListener( port );

tcpl->Start();

Console::WriteLine(

S"Server[{0}]: OK: started TcpListener ... ",

__box( port ));

// retrieve the data from the data base ...

Thread *tdata =

new Thread( new ThreadStart( this,

&SocketDemo_Server::retrieveData ));

tdata->Start(); // ok: kick off the thread ...

// thread to handle a socket connection ...

Thread *tconnect =

new Thread( new ThreadStart( this,

&SocketDemo_Server::handleConnection ));

tconnect->Start();

}

catch( Exception *ex )

{

Console::WriteLine(

S"Oops: Unable to Set Up SocketDemo_Server" );

Console::WriteLine( ex->ToString() );

}

}

我們看到,Start 函式利用 Thread 類生成許多執行緒,分別響應每位客戶的請求。此外,由於 WriteLine 函式需要引用引數,故我們使用了 __box( port ) 。

再有,Exception 類是一切 .NET 的異常處理類的基類;ToString 方法用於顯示整個堆疊 (酷極了); ThreadStart 是 代表 (delegate) 型別 —— 既能指向靜態成員函式,也能指向動態成員函式的通用指標型別。

當然,它的實現程式碼還可以進一步完善,但是我想您現在已經體會到 .NET 框架的強大和易用性了。更重要的是,您已經看到,在 C++ 裡面使用它是多麼的簡單!

C++ 的未來

本文是對 Visual Studio .NET 下的 C++ 的簡單介紹,希望在讀過之後,您會對 Visual C++ 充滿信心,因為它不僅僅是 Visual Studio .NET 中的一份子,而且是其重要的一員。為了體現其重要性,微軟公司 Visual C++ 工作組正在努力工作以爭取儘早完成新一代 Visual C++ 的過渡版本,它將具有本文所述的全部新特性。在 ISO 標準 C++ 的相容性方面,工作組已經邁出了一大步。對於優秀的程式設計師來說,它意味著模板,模板,還是模板!諸如 Loki 和 Boost 等大量使用模板的第三方程式庫,正在緊張工作中。正如人們在電影中說的那樣:“瞧著吧,好戲還在後頭呢!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-946142/,如需轉載,請註明出處,否則將追究法律責任。

相關文章