C++_CLI语言标准草案翻译节选-语言概述8_2

类别:编程语言 点击:0 评论:0 推荐:
8.2.1基础类型和CLI
每个基础类型是CLI提供类型的缩写符。例如,关键字int等同于有值类System::Int32 。作为一个风格的问题,更倾向于使用关键字而不是使用完整的系统类型名字。
下面的这张表列出了基础类型和他们对应的CLI提供的类型:这对应关系还处于讨论之中,它现在还没有办法完全定下来!(译者注:下面本来有一张表示基础类型与CLI提供类型的对应表,但是由于文本格式以及上文提及的关系,没有给出这张表。其中的对应关系很明显,而且没有它也完全不影响读者阅读、理解下面的内容。)
8.2.2转化
一些新型的转化被定义。其中包含了句柄和参数数组的转化。
8.2.3数组类型
一个C++/CLI中的数组不同于原生数组,后者分配在CLI堆。而且可以有不只一个的阶(rank)。该阶决定每个数组元素的索引数量。一个数组的阶同时也被称为数组的维数。一个一阶的数组被称为一维数组。而超过一阶的数组被称为多维数组。
在这个标准中,数组(Array)在被用来指代CLI数组。一个C++数组被称为原生数组(native array)。不管什么时候,区别他们是需要的。
8.2.4类型系统统一
C++/CLI提供了一个“统一的类型系统”,所有的值和句柄类型导出于类型System::Object .
在任何任何值上调用实例函数是可能的,哪怕是如int这样的基础类型的值。
这个例子
int main() {
    Console::WriteLine((3).ToString());
}
从类型System::Int32对一个整型文字量上调用函数ToString,结果输出3。(注意,3旁边看起来多余的圆括号并不是多余的,它们用于得到标记"3"和".",而不是"3.")。
这个例子
int main() {
    int i = 123;
    Object^ o = i; // boxing
    int j = static_cast<int>(o); // unboxing
}
更有趣,一个整型值可以被转成System::Object再回到int。这里展示了装箱(boxing)和(unboxing)。当一个值类型的变量要转成句柄类型,一个对象盒子(box)被分配来安放值,值被复制放入盒子(box)。拆箱(Unboxing)则正好反过来,对象盒子(box)转换回到它原有的有值类,值被从box复制出来并放入适当的存储空间。
这个类型系统统一提供了值类型作为对象的好处而没有引入不必要的开销。对于不需要int值做对象的程序,Int值是32-bit值。但对于需要int象对象那样工作的程序,只要需要就能得到这种能力。这种使值类型作为对象的能力填补了在大多数语言中都存在的值类型语句柄类型的鸿沟。例如一个Stack类可能提供Push和pop函数返回Object^值。
public ref class Stack { public:
    Object^ Pop() {…}
    void Push(Object^ o) {…}
};
因为C++/CLI有一个统一的类型系统,Stack类可以使用任何类型的元素。包括值类型int.(译者注:这东西目前看起来价值有限,在有了静态模板的C++面前,的确不怎么吸引人。在节约空间以外,希望它能做得更多。静态模板在使用了一些小技巧以后,也能达到动态模板的空间开销,同时还能拥有静态类型检查)
8.2.5指针,句柄和null
标准C++支持指针类型和空指针常量。C++/CLI加入句柄和空值,为了帮助整合句柄,并且有一个普遍的空值,C++/CLI定义关键字nullptr .这关键字表示一个有空类型的文字量。nullptr 就是null value constant.(不能创建空类型的事例,仅有的方法去获得一个空值常量就是通过这个关键字。
空指针常量的定义(标准C++要求编译时间能被计算出结果为0的表达式)被延伸包含nullptr。空值常量可以隐式转成指针或句柄类型,它分别变成空指针值或空值。 这允许nullptr用于比较大小的,相等性的,条件的和赋值等的表达式。
Object^ obj1 = nullptr; // 句柄 obj1 有空值。
String^ str1 = nullptr; // 句柄 str1 有空值
if (obj1 == 0); // false (0被装箱,然后两个句柄不相等)
if (obj1 == 0L); // false “ “ “ “ “
if (obj1 == nullptr); // true
char* pc1 = nullptr; // pc1 是空指针值
if (pc1 == 0); // true 当0作为空指针值
if (pc1 == 0L); // true “ “ “
if (pc1 == nullptr); // true ,这个时候nullprt作为空指针值
int n1 = 0;
n1 = nullptr; // error, 没有从nullptr到int的隐式的转换
if (n1 == 0); // true, 进行整数比较
if (n1 == 0L); // “ “ “
if (n1 == nullptr); // error, 没有从nullptr到int的隐式的转换
if (nullptr); // error没有从nullptr到bool的隐式的转换
if (nullptr == 0); // error, 没有从nullptr到int的隐式的转换
if (nullptr == 0L); // “ “ “
nullptr = 0; // error, nullptr不是一个左值
nullptr + 2; // error, nullptr 不能参与算术计算
Object^ obj2 = 0; // obj2 是个0装箱后的句柄
Object^ obj3 = 0L; // obj3 “ “ “
String^ str2 = 0; // error, 没有从int到String^的隐式的转换
String^ str3 = 0L; // “ “ “ “
char* pc2 = 0; // pc2 是空指针值
char* pc3 = 0L; // pc3 “ “ “
Object^ obj4 = expr ? nullptr : nullptr; // obj4 是空值
Object^ obj5 = expr ? 0 : nullptr; // error, 没有相容的类型
char* pc4 = expr ? nullptr : nullptr; // pc4 是空指针值
char* pc5 = expr ? 0 : nullptr; // error, 没有相容的类型
int n2 = expr ? nullptr : nullptr; // error, 没有到int的隐式转换
int n3 = expr ? 0 : nullptr; // error, 没有相容的类型
sizeof(nullptr); // error,空类型没有大小
throw nullptr; // error
void f(Object^); // 1
void f(String^); // 2
void f(char*); // 3
void f(int); // 4
f(nullptr); // error, 二义 (1, 2, 3 都可能)
f(0); // calls f(int)
void g(Object^, Object^); // 1
void g(Object^, char*); // 2
void g(Object^, int); // 3
g(nullptr, nullptr); // error, 二义  (1, 2 都可能)
g(nullptr, 0); // calls g(Object^, int)
g(0, nullptr); // error, 二义(1, 2 都可能)
void h(Object^, int);
void h(char*, Object^);
h(nullptr, nullptr); // 调用 h(char*, Object^);
h(nullptr, 2); // 调用  h(Object^, int);
template<typename T> void k(T t);
k(0); // 特殊化 k, T = int
k(nullptr); // error, 不能实例化nullptr
k((Object^)nullptr); // 特殊化 k, T = Object^
k<int*>(nullptr); // 特殊化 k, T = int*
因为分配在本地堆的对象无法移动,该对象指针不需要追踪对象的位置。然而,CLI堆的对象可以移动,所以它们需要追踪。同样的,原生的指针不足以应付它们。为了追踪对象,C++/CLI定义了句柄(使用符号 ^)并追踪参考(使用符号 %)
N* hn = new N; // 分配在原生堆
N&rn=*hn; // 对原生指针绑定普通引用
R^ hr = gcnew R; // 分配在CLI堆上
R% rr = *hr; //绑定追踪引用到gc左值(gc-lvalue)上
通常,%对于^就象&对于*一样。
标准C++有一个一元&操作符,C++/CLI提供一元%操作符。当&t产生T*或一个interior_ptr<T>,%t产生一个T^。
右值和左值继续拥有标准C++的相同意义。按照下列规定:
•一个实体声明类型T*,就是一个原生指针T,指向一个左指。
•对一个实体声明类型T*应用一元*,就是解引用T*,产生一个左值。
•一个实体声明类型T&,就是一个原生引用T,是一个左值。
•表达式& 左值产生T*。
•表达式% 左值产生T^。
一个gc左值(gc-lvalue)是一个从CLI堆引用对象,或是引用这样的对象包含的一个值成员的表达式。对gc-lvalues有下列规则:
•从“cv-qualified lvalue of type T“到“cv-qualified gc-lvalue of typeT”存在标准转化,同样也存在于“cv-qualified gc-lvalue of type T ” 到“cv-qualified rvalue of type T .”
(译者注:抱歉,我实在是看不懂上面在说什么。)
•一个声明类型为T^实体 ,句柄T,指向gc-左值(gc-lvalues).
•对一个声明类型为T^的实体应用一元*,解引用T^,产生一个gc-左值(gc-lvalues).
•一个声明类型为T&实体,追踪参考T,是一个gc-左值(gc-lvalues)。
•表达式& gc左值(gc-lvalue)产生一个interior_ptr<T>。
•表达式% (gc-lvalue)产生T^。
垃圾收集器被允许在CLI堆上移动聚集其上的对象。为了让一个指针正确的引用到这样的一个对象,运行时环境需要更新那个指针到对象的新的位置。一个内务(内部,interior)指针(用interior_ptr来定义)就是以这样一个方式更新的指针。

本文地址:http://com.8s8s.com/it/it23468.htm