Visual C++.NET 2010开发实践:基于C++/CLI
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3 基本数据类型

C++/CLI与标准C++相同,它们都是一种强类型语言,在程序中用到的变量、表达式和数值等都必须有特定的类型,在编译程序时编译器会检查所有数据类型操作的合法性。

1.3.1 基本数据类型

C++/CLI中的基本数据类型大多与标准C++的基本数据类型相同,并且算术运算也相同。然而,C++/CLI中新定义了两种整数类型long long和unsigned long long,这两种数据类型分别占用64位(8字节)空间,可以表示-263~263-1范围的有符号整数和0~264-1范围的无符号整数。

当为long long数据类型的变量赋值时,需要在整数数值的后面加上LL或者ll后缀;而当为unsigned long long数据类型的变量赋值时,则需要在整数数值的后面加上ULL或者ull后缀。例如:

        longlong value1 = 123456789LL;
        unsigned long long value2 = 123456789ULL;

在C++/CLI中,每种基本类型都在System命名空间中定义了相应的值类类型。可以将基本数据类型值在对应的值类型之间相互转换。C++/CLI的基本数据类型及对应的值类类型如表1.3所示。

表1.3 C++/CLI的基本数据类型及对应的值类类型

在默认情况下,char类型被视为singed char,因此其关联的值类类型为System::SByte。如果编译选项/J,则char默认为unsigned char,此时关联的值类类型为System::Byte。

此外System空间中还定义了许多其他类型,如表示字符串的String类型、精确存储的十进制小数类型Decimal等。Decimal类型适用于要求使用大量有效的整数及小数位数的情况,并且其精度达到28位。Decimal类型并不会消除对舍入的需要,而是尽可能地提高数值精度以将因舍入而导致的错误程度降到最低。例如:

        System::Decimal dividend = 1;
        System::Decimal divisor = 3;
        System::Decimal result=dividend/divisor;//result=0.3333333333333333333333333333

1.3.2 装箱与拆箱

在C++/CLI中,关联的值类类型为基本类型添加了重要的附加功能。当编译器需要时,将安排原值与关联类型之间的自动转换,其中从原值转换为关联类型称为装箱(boxing),反之称为拆箱(unboxing)。根据上下文环境,这些变量将表现为简单的值或者对象。

由于标准C++基本类型的名称是C++/CLI程序中值类类型名称的别名,所以原则上C++/CLI代码中可用任何一种名称。例如:

        int count = 10;
        double value = 2.5;

等价于:

        System::Int32 count = 10;
        System::Double value = 2.5;

将基本类型转换为值类类型是C++/CLI的一个重要特征。在标准C++中基本类型与类类型完全不同,而在C++/CLI中,所有数据都以类类型的形式存储,包括值类型(存储在堆栈上)和引用类型(存储在堆上)。

【例1.5】 装箱、拆箱的示例。在main函数中分别定义一个值类型和一个引用类型的双精度浮点数,然后将这两个数装箱到Object对象中。代码如下:

        // Ex1_5.cpp: 主项目文件
        #include "stdafx.h"
        using namespace System;
        int main(array<System::String ^> ^args)
        {
            double result = 3.14159;
            Console::WriteLine(L"result的值为: {0}", result.ToString());
            double^ br = result;
            Console::WriteLine(L"br的值为: {0}", br->ToString());
            result = 2.7;
            *br = 2.17;
            Console::WriteLine(L"result与br的值分别为: {0}, {1}", result, br);
            Object^ obj = br;
            Console::WriteLine(L"obj的值为: {0}", obj);
            Console::WriteLine(L"隐式装箱:(3).ToString()输出为:{0}", (3).ToString());
            return 0;
        }

当Ex1_5项目运行后,其执行结果如图1.9所示。

图1.9 Ex1_5项目的运行结果

1.3.3 强制类型转换

在实际编程应用中,经常会遇到类型的相互转换问题。在CLR环境中,通常使用safe_cast显式地对类型进行强制转换。safe_cast的用法与static_cast的用法相同,它们都在关键字后通过尖括号对(“< >”)来指定转换后的新类型,并在括号(“( )”)中指定需要转换的变量和表达式。其用法如下:

      [cli]::static_cast<type-id>(expression)

当使用static_cast进行类型的转换时是强制性的,并没有在任何运行过程进行类型检查来保证转换的正确性,所以编程人员需要明白自己所进行的转换是否合理。但是,若使用safe_cast进行类型转换时,编译器将不产生转换错误,而是在运行时进行检查并判断转换是否可行。如果safe_cast在将一种类型转换为另一种类型时不成功,那么产生错误。例如:

        double value1 = 10.5, value2 = 15.5;
        int^ sum = safe_cast<int>(value1 + value2);
        String^ str = safe_cast<String^>(sum);//error C2682:不能从int^转换到String^类型

另外,在System命名空间中还提供了Convert类用于将一个基本数据类型转换为另一个基本数据类型。Convert类还支持将任何自定义类型转换为任何基类型,但是自定义类型必须实现IConvertible接口,以定义将实现类型转换为每个基类型的方法。Convert类中常用的转换方法如表1.4所示。

然而,使用Convert类对基本数据类型进行类型转换时,可能会产生InvalidCastException异常、FormatException异常或OverflowException异常。其中,如果在不支持特定类型的转换时将产生InvalidCastException异常;而若由于字符串格式不正确而导致将字符串值转换为任何其他基类型时,则将产生FormatException异常;如果将大范围数据类型转换为小范围的数据类型,并导致超出小范围数据类型的表示范围时,将产生OverflowException异常。

表1.4 Convert类中常用的转换方法

【例1.6】 类型强制转换的示例。在main函数中分别调用Convert类中的类型转换函数将double类型的数转换为整型、bool类型、字符串类型等。代码如下:

          // Ex1_6.cpp: 主项目文件
          #include "stdafx.h"
          using namespace System;
          int main(array<System::String ^> ^args)
          {
              Double dNumber = 23.15;
              try {
                Int32  iNumber = Convert::ToInt32(dNumber);
                Console::WriteLine(L"Double类型{0} 转换为整型:{1}",dNumber,iNumber);
              }
              catch (OverflowException^ e) {
                Console::WriteLine(L"范围溢出: {0}", e->ToString());
              }
              Boolean bNumber = Convert::ToBoolean(dNumber);
              Console::WriteLine(L"Double类型{0} 转换为bool类型:{1}",dNumber,bNumber);
              String^ strNumber = Convert::ToString(dNumber);
            Console::WriteLine(L"Double类型{0}转换为String类型:{1}", dNumber,strNumber);
              try {
                Char chrNumber = Convert::ToChar(strNumber->Substring(0, 1));
                Console::WriteLine(L"将字符串{0} 转换为Char类型: {1}",
                    strNumber->Substring(0, 1), chrNumber);
              }
              catch (FormatException^ e) {
                Console::WriteLine(L"字符串格式错误: {0}", e->ToString());
              }
              return 0;
          }

当Ex1_6项目运行后,其执行结果如图1.10所示。

图1.10 Ex1_6项目的运行结果