选择显示字体大小

c++/clr泛型与c++模板之间的对比


  visual studio 2005把泛型编程的类型参数模型引入了微软.net框架组件。c++/cli支持两种类型参数机制--通用语言运行时(clr)泛型和c++模板。本文将介绍两者之间的一些区别--特别是参数列表和类型约束模型之间的区别。

  参数列表又回来了

  参数列表与函数的信号(signature)类似:它标明了参数的数量和每个参数的类型,并把给每个参数关联一个唯一的标识符,这样在模板定义的内部,每个参数就可以被唯一地引用。

  参数在模板或泛型的定义中起占位符(placeholder)的作用。用户通过提供绑定到参数的实际值来建立对象实例。参数化类型的实例化并非简单的文本替代(宏扩展机制就是使用文本替代的)。相反地,它把实际的用户值绑定到定义中的相关的形式参数上。

  在泛型中,每个参数都表现为object类型或衍生自object的类型。在本文后面你可以看到,这约束了你可能执行的操作类型或通过类型参数声明的对象。你可以通过提供更加明确的约束来调整这些约束关系。这些明确的约束引用那些衍生出实际类型参数的基类或接口集合。

  模板除了支持类型参数之外,还支持表达式和模板参数。此外,模板还支持默认的参数值。这些都是按照位置而不是名称来分解的。在两种机制之下,类型参数都是与类或类型名称关键字一起引入的。

  参数列表的额外的模板功能

  模板作为类型参数的补充,允许两种类型的参数:非类型(non-type)参数和模板参数。我们将分别简短地介绍一下。

  非类型参数受常数表达式的约束。我们应该立即想到它是数值型或字符串常量。例如,如果选择提供固定大小的堆栈,你就可能同时指定一个非类型的大小参数和元素类型参数,这样就可以同时按照元素类别和大小来划分堆栈实例的类别。例如,你可以在代码1中看到带有非类型参数的固定大小的堆栈。

  代码1:带有非类型固定大小的堆栈

template <class elemtype, int size>
public ref class tstack
{
 array<elemtype> ^m_stack;
 int top;

 public:
  tstack() : top( 0 )
  { m_stack = gcnew array<elemtype>( size ); }
};

  此外,如果模板类设计者可以为每个参数指定默认值,使用起来就可能方便多了。例如,把缓冲区的默认大小设置为1kb就是很好的。在模板机制下,可以给参数提供默认值,如下所示:

// 带有默认值的模板声明
template <class elemtype, int size = 1024>
public ref class fixedsizestack {};

  用户可以通过提供明确的第二个值来重载默认大小值:

// 最多128个字符串实例的堆栈
fixedsizestate<string^, 128> ^tbs = gcnew fixedsizestack<string^, 128>;

  否则,由于没有提供第二个参数,它使用了相关的默认值,如下所示:

// 最多1024个字符串实例的堆栈
fixedsizestack<string^> ^tbs = gcnew fixedsizestack<string^>;

  使用默认的参数值是标准模板库(stl)的一个基本的设计特征。例如,下面的声明就来自iso-c++标准:

// iso-c++名字空间std中的默认类型参数值示例
{
 template <class t, class container = deque<t> >
 class queue;

 template <class t, class allocator = allocator<t> >
 class vector;
 // ...
}

  你可以提供默认的元素类型,如下所示:

// 带有默认的元素类型的模板声明
template <class elemtype=string^, int size=1024>
public ref class tstack {};

  从设计的角度来说很难证明它的正确性,因为一般来说容器不会集中在在单个默认类型上。

  指针也可以作为非类型参数,因为对象或函数的地址在编译时就已知了,因此是一个常量表达式。例如,你可能希望为堆栈类提供第三个参数,这个参数指明遇到特定条件的时候使用的回调处理程序。明智地使用typedef可以大幅度简化那些表面上看起来很复杂的声明,如下所示:

typedef void (*handler)( ... array<object^>^ );
template <class elemtype, int size, handler cback >
public ref class tstack {};

  当然,你可以为处理程序提供默认值--在这个例子中,是一个已有的方法的地址。例如,下面的缓冲区声明就提供了大小和处理程序:

void defaulthandler( ... array<object^>^ ){ ... }

template < class elemtype,
int size = 1024,
handler cback = &defaulthandler >
public ref class tstack {};

  由于默认值的位置次序优先于命名次序,因此如果不提供明确的大小值(即使这个大小与默认值是重复的),就无法提供重载的处理程序的。下面就是可能用到的修改堆栈的方法:

void demonstration()
{
 // 默认的大小和处理程序
 tstack<string^> ^ts1 = nullptr;
 // 默认的处理程序
 tstack<string^, 128> ^ts2 = gcnew tstack<string^, 128>;
 // 重载所有的三个参数
 tstack<string^, 512, &yourhandler> ^ts3;
}

  模板支持的第二种额外的参数就是template模板参数--也就是这个模板参数本身表现为一个模板。例如:

// template模板参数
template <template <class t> class arena, class arenatype>
class editor {
arena<arenatype> m_arena;
// ...
};

  editor模板类列出了两个模板参数arena和arenatype。arenatype是一个模板类型参数;你可以传递整型、字符串型、自定义类型等等。arena是一个template模板参数。带有单个模板类型参数的任何模板类都可以绑定到arena。m_arena是一个绑定到arenatype模板类型参数的模板类实例。例如:

// 模板缓冲区类
template <class elemtype>
public ref class tbuffer {};

void f()
{
 editor<tbuffer,string^> ^texteditor;
 editor<tbuffer,char> ^bliteditor;
 // ...
}


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons