分享
 
 
 

情有独钟C++:Visual C++ .NET编译器的新特性

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

广州市天河村迎福七巷9号 王凌峰

本文假定您已熟悉 C++ 。

摘要

老资格的 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<NotQuery*>(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 <algorithm>

#include <string>

#include <vector>

#include <utility>

#include <map>

#include <set>

#include <iostream>

#include <fstream>

#include <stddef.h>

#include <ctype.h>

using namespace std;

创建的数据结构如下:

typedef pair<short,short> location;

typedef vector<location> loc;

typedef vector<string> text;

typedef pair<text*,loc*> text_loc;

class TextQuery {

public:

// ...

private:

vector<string> *lines_of_text;

text_loc *text_locations;

map<string,loc*> *word_map;

Query *query;

static string filt_elems;

vector<int> 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 <mscorlib.dll>

#include <tchar.h>

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 <mscorlib.dll>

#using <System.dll>

#using <System.Data.dll>

#using <System.Xml.dll>

// 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 等大量使用模板的第三方程序库,正在紧张工作中。正如人们在电影中说的那样:“瞧着吧,好戏还在后头呢!”

.a1{font-size:1}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有