C++:最强大的.NET语言之装箱

再论类型

  在讨论装箱(boxing)之前,有必要弄清楚为什么值类型与引用类型之间会有所区别。

  一个含有数值的值类型的实例,和一个指向对象的引用类型的实例,它们有什么区别呢?除了存储对象所需的内存之外,每一个对象都会有一个对象头,目的是为面向对象的编程提供基本的服务,如存在虚方法的类,嵌入其中的元数据等等。由虚方法和接口间接结合的对象头,其内存开销通常会很大,哪怕你所需要的只是一个静态类型的数值,也会带来一些编译器的强制操作。有趣的是,在某些情况下,编译器能优化掉一些对象开销,但不总是能起作用。如果你非常在意托管代码的执行效率,那么使用数值或值类型将会有所益处,但在本地C++的类型中,这不算一个很大的区别,当然,C++也没有强制任何编程范式,所以也有可能在C++之上,通过创建库来建立一个这样截然不同的类型系统。

  装箱

  什么是装箱(boxing)?装箱是一种用来桥接数值和对象的机制。尽管CLR的每种类型都是直接或间接从Object类派生而来,但数值却不是。一个堆栈上的数值(如整形int),只不过是一个编译器会进行某种特定操作的内存块。如果你实在想把一个数值当成一个对象,必须对数值调用从Object继承而来的方法,为了实现这一点,CLR提供了装箱的概念。知道一点装箱的原理还是有点用的,首先,一个数值通过使用ldloc IL指令入栈,接下来,装箱IL指令运行,把数值类型提升,CLR再把数值出栈,并分配足够的空间存储数值与对象头,然后一个对新建对象的引用被压入栈,所有这些就是装箱指令要做的事。最后,为取得对象引用,stloc IL指令从堆栈中弹出引用,并把它存储在局部变量中。

  现在,问题是:在编程语言中,对数值的装箱操作,是应该表现为隐式还是显式呢?换句话说,是否应使用一个显式转换或其他构造函数呢?C#语言设计者决定做成隐式转换,毕竟,一个整形数是从Object间接继承来的Int32类型。

int i = 123;
object o = i;
   问题来了,正如我们所知,装箱不是一个简单的向上转换,它有点像把一个数值转换成一个对象,是一个存在潜在代价的操作。正是因为这个原因,托管C++通过使用关键字__box,来进行显式装箱。

int i = 123;
Object* o = __box(i);
  当然,在托管C++中,当装箱一个数值时,不会失去静态类型信息,而这一点,正是C#所缺乏的。

int i = 123;
int __gc* o = __box(i);
  指定强类型的装箱值有利于再次转换回到一个数值类型,或被称为解箱(unboxing),不使用dynamic_cast,只是简单地解引用一个对象。

int c = *o;
  当然,托管C++的显式装箱所带来的句法上的花销,在许多情况下已被证明是巨大的。正因为此,改变了C++/CLI语言的设计过程,成了与C#保持一致--隐式装箱。在相同情况下,它在直接表示强类型装箱数值上保持了类型安全,而这正是其他 .NET语言所做不到的。

int i = 123;
int^ hi = i;
int c = *hi;
hi = nullptr;
  在此,也暗示着一个没有指向任何对象的句柄,不能被初始化为零,在这一点上,与指针是一致的,因为这将导致只是把数值"零"装箱;同时这也是常量nullptr存在的原因,它能被赋给任何句柄,且是C#中关键字null的对等物。尽管在C++/CLI语言设计中,nullptr是一个新的保留字,但它已被Herb Sutter和Bjarne Stroustrup提议增加在标准C++中。

编写引用和值类型

   在C#中,通常用关键字class来声明一个引用类型,而用关键字struct来声明值类型: class ReferenceType {}
struct ValueType {}
  对于class和struct,C++已经有定义好了的含义,所以这在C++中行不通。在最初的语言设计上,放置在类前的关键字__gc表示这是一个引用类型,而关键字__value则表示这是一个值类型。

__gc class ReferenceType {};
__value class ValueType {};
  C++/CLI在那些不会与用户的其他标识符发生冲突的地方引入了"空隔"关键字。为了声明一个引用类型,只需在class或struct之前加上ref,类似地,可用value来声明值类型。

ref class ReferenceType {};
ref struct ReferenceType {};

value class ValueType {};
value struct ValueType {};
  关于使用class还是struct,与默认状态下类成员的可见度有关,在CLR中,最大的不同之处在于,只支持公有继承。使用private(私有)或protected(保护)继承都将会导致编译错误,因此,显式声明公有继承是合法但却多余的。

时间: 2024-09-20 05:28:49

C++:最强大的.NET语言之装箱的相关文章

C++:最强大的.NET语言之对象构造

简介 Visual C++开发小组花了大量的时间用于听取用户的意见,在对 .NET和C++经过仔细考量之后,决定在Visual C++ 2005中重新设计对通用语言运行时库(CLR)的支持,此项重新的设计被称为"C++/CLI",它将为使用及编写CLR类型提供更自然的语法.在本文中,主要探讨了新的语法,并将之与C#和托管C++这两个CLR平台上极其相近的语言进行比较,在文中也会适当地以图表给出其与本地C++的相似之处. 通用语言运行时库(CLR)包括了一组规范,其是Microsoft

C++:最强大的.NET语言之可访问性

CLR定义了一些用于访问存取的修饰成分,其作用超越了本地C++中类成员函数与变量的对等物(如:public.private.protected),不仅如此,甚至还能定义命名空间或嵌套类型的可访问性.为了让C++/CLI达到作为低级语言的目标,除访问性之外,它还提供了比其他CLR平台高级语言更多的控制. 本地C++可访问性与CLR中定义的可访问性相比,其最大不同之处在于:本地C++访问指示符通常用于限制同一程序中从其他代码访问类成员:而CLR定义的类型和成员的可访问性,不只是针对同一程序集中的其他

C++:最强大的.NET语言之内存与资源

当运行环境中包含垃圾回收机制时,区别开内存管理和资源管理,就非常重要了.典型地来说,垃圾回收器只对包含对象的内存之分配与释放感兴趣,它可不关心你的对象是否拥有其他的资源,如数据库连接或核心对象的句柄. 内存管理 本地C++为程序员提供了超越内存管理的直接控制能力,在堆栈上分配一个对象,意味着只有在进入特定函数时,才会为对象分配内存,而当函数返回或堆栈展开时,内存被释放.可使用操作符new来动态地为对象分配内存,此时内存分配在CRT堆中,并且需要程序员显存地对对象指针使用操作符delete,才能释

入门必读 机器学习六大开发语言

机器学习的初学者,普遍需要面对一个问题: 到底学习哪个编程语言? 答案可能会让你惊讶:对高手来说,这关系不大.只要你了解所选语言的机器学习库和工具,语言本身其实没那么重要.相当多的机器学习库支持多种编程语言.当然,取决于你在公司中的开发角色和你需要实现的任务,有些语言.库和工具会比其他的更高效.下面,我们来看看六大主流机器学习语言--R 语言.MATLAB.Python.Java .C/C++ 和 Lisp. R 语言 R 是一个专门设计来进行数据计算的语言工具.在大规模数据挖掘.可视化和报告的

VC++ 2005快速构建安全的应用程序

一. 简介 微软的Visual C++2005发布版本对于有志于轻松.迅速地编写安全可靠的应用程序的编程爱好者来说是正确地选择.正如你所听到的那样,Visual C++中语言和库的新特点使开发安全.可靠的应用程序比以前更容易.它即提供了功能强大并且灵活的标准C++,又提供了适于.NET框架下编程的最强大的开发语言. 本文中,我主要探讨Visual C++2005发布版本中部分语言和库的新特色,无论是对于教学项目还是大的应用工程,这都将帮助你在编写安全可靠的代码时提高工作效率. 二.C运行时库的安

CSS预处理器语言sass语法:学习sass语法

文章简介:其实现在的Sass已经有了两套语法规则:一个依旧是用缩进作为分隔符来区分代码块的:另一套规则和CSS一样采用了大括号({})作为分隔符.后一种语法规则又名SCSS,在Sass3之后的版本都支持这种语法规则.我们这里讨论的如无特殊说明,全指scss. 什么是sass? Sass是是一种基于ruby编写的CSS预处理器,诞生于2007年,是最早也是最成熟的一款CSS预处理器语言,它可以使用变量.嵌套.混入.继承,运算,函数等功能,使得CSS的开发,变得简单清晰可维护,同时也大大节省了设计者

Java1.5语言新特性简单总结

1. 自动装箱与拆箱 对应C# 例1.1  Integer i = 10;  int j = i;  2. 更优化的for循环 对应就C#---foreach循环 例2.1  String[] names = {"BadBoy","GoodBoy","HappyGirl","sadGirl"};  for(String option: names) {   System.out.println(option);  } 例2.2

J2SE 5.0专题 之 语言特性

j2se J2SE 5.0专题 之 语言特性                         本文作者: 高宇翔(大胃) 1.1.        背景J2SE(TM) 5.0正式发布至今已超过3个月的时间了,就在前不久,大概是在两周之前,Sun又发布了更新过的JDK 5.0 Update 1,改掉了一些第一个版本中出现的bug. 由于Java社群等待这一从1.4向5.0版本升级已经有相当长的一段时间,大家都很关心5.0中有哪些值得关注的变化,于是blog的相关信息满天飞,我也兴冲冲地在自己的bl

草根的进化 PHP语言发展简史

PHP 继承自一个老的工程,名叫 PHP/FI.PHP/FI 在 1995 年由 Rasmus Lerdorf 创建,最初只是一套简单的 Perl 脚本,用来跟踪访问他主页的人们的信息.它给这一套脚本取名为"Personal Home Page Tools".随着更多功能需求的增加,Rasmus 写了一个更大的 C 语言的实现,它可以访问数据库,可以让用户开发简单的动态 Web 程序.Rasmus 发布了 PHP/FI 的源代码,以便每个人都可以使用它,同时大家也可以修正它的 Bug