C++的类型转换

发布时间:2024年01月17日

前言

本篇文章讲解C++的类型转换
C++中的类型转换分为隐式转换和显式转换

隐式转换

隐式转换是指编译器根据我们数据类型自动调整部分数据类型的转换过程,因为是编译器管理的,所以,我们必须知道编译器的转换规则。

根据数据类型的不同,隐式转换分为

  • 算术类型转换
  • 数组转换成指针
  • 指针的转换
  • 转换成布尔类型
  • 类类型的转换

算术类型转换

要想弄清算术类型的转换规则,首先得知道编译器在进行算术类型转换的时候的原则:

  • 算术类型之间的隐式转换被设计得尽可能避免损失精度。如果表达式中既有整数类型的运算对象也有浮点数类型的运算对象,整型会转换成浮点型
    int main(int argc, const char* argv[])
    {
    	long long a = 1;
    	float b = 1.2;
    	std::cout << typeid(a + b).name() << std::endl;
    	return 0;
    }
    
    最后结果输出float。
    在a + b的运算过程中,整形a会转换成浮点数b,因为没有浮点数和整数运算的指令,所以编译器会尽量保持精度的准确
  • 对于bool、char、signed char、unsigned char、short 和unsigned short 等类型来说, 只要它们所有可能的值都能存在int里,它们就会提升成int类型,否则,提升成unsigned int类型,这叫做整型提升。看下面代码:
    int main(int argc, const char* argv[])
    {
        bool a;
        char b = 'c';
        signed char f = 'f';
        unsigned char c= 'd';
        short d = 10;
        unsigned short e = 10;
        int g = 20;
    
        std::cout << typeid(a + a).name() << std::endl;
        std::cout << typeid(b + b).name() << std::endl;
        std::cout << typeid(c + c).name() << std::endl;
        std::cout << typeid(d + d).name() << std::endl;
        std::cout << typeid(e + e).name() << std::endl;
        std::cout << typeid(f + f).name() << std::endl;
        std::cout << typeid(g + g).name() << std::endl;
    }
    
    输出结果全部都是int
  • 如果表达式中存在两种不同类型的整形,通常表示范围小的类型要转化成表示范围大的类型,比如:
    • int和long:int会转化成long
    • short和int:short会转化成int
    • char和int:char会转换成int
      看下面的例子:
      int main(int argc, const char* argv[])
      {
          int a = 1;
          long b = 2;
          long long c = 3;
      
          std::cout << typeid(a + b).name() << std::endl;
          std::cout << typeid(b + c).name() << std::endl;
          std::cout << typeid(a + c).name() << std::endl;
      }
      
      输出结果为:
      long
      __int64
      __int64
      
  • 如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型。如果不能,那么带符号类型的运算对象转换成无符号类型。看下面代码:
    int main(int argc, const char* argv[])
    {
        unsigned short a = 1;
        unsigned int b = 1;
        long c = 2;
    
        std::cout << typeid(a + c).name() << std::endl;
        std::cout << typeid(b + c).name() << std::endl;
    }
    
    结果为:
    long
    // unsigned int和long都是四个字节,所以b无法转换成c,c由long转换成unsigned long
    unsigned long
    

数组转指针

在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针

指针的转换

C++还规定几种其他的指针转换方式,包括

  • 常量整数值或者字面值nullptr能转换成任意指针类型
  • 指向任意非常量的指针能转换成void*
  • 指向任意对象的指针或引用能转换成常量指针或引用,但是反过来不成立。

转换成布尔类型

存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换结果是false,否则转换结果是true

类类型的转换

类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换

显式转换

显式转换也叫强制类型转换,显式转换表示转换结果由程序员自己负责,所以要慎重。有四种强制转换方法:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast

static_cast

任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast,这也是我们使用最多的类型转换,想象C语言中的显式转换方法,看下面代码:

long c = 2;
unsigned short a = (unsigned short)c;

这种是C语言的用法,我们可以使用static_cast实现相同的意思

long c = 2;
unsigned short a = static_cast<unsigned short>(c);

dynamic_cast

动态类型转换,编译器不进行转换检查
能将父类的指针或者引用安全地转换为子类的指针或者引用。

const_cast

const_cast只能改变指针或者引用的底层const
一旦我们去掉了某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。 如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。 然而如果对象是一个常量,再使用const_cast 执行写操作就会产生未定义的后果,看下面的例子:

int main(int argc, const char* argv[])
{
    const int a = 90;
    const int* p = &a;
    int* b = const_cast<int*>(p);
    *b = 120;
    std::cout << *b << std::endl;
    std::cout << a << std::endl;
}

上面打印的结果是

120
90

也就是说对于const int a来说,虽然通过const_cast去掉了对应指针的底层const,但是a毕竟是一个常量。所以不要这样去改变a的值。

但是如果a不是一个常量,我们把

const int a = 90;

改成

int a = 90;

打印的结果是

120
120

总结一下:
const_cast应该用于那些本来不是常量,但是后来可能经过一系列操作,比如参数传递,变成了const类型,这种情况我们可以使用const_cast来去掉const的限制。

reinterpret_cast

reinterpret_cast可以实现任意类型的转换,并且编译器不会给出任何警告或者错误提示。要谨慎使用转换后的值。

文章来源:https://blog.csdn.net/b1049112625/article/details/135642671
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。