【C++】C++的类型转换

简介: 【C++】C++的类型转换

1. C语言中的类型转换


在C语言中,经常会出现一种情况:运算符两边的类型不同,或者形参实参类型不匹配,此时就会发生类型转化。在C语言中,类型转化分为两种:隐式类型转换和显式类型转换

  1. 隐式类型转换:编译器在变异阶段自动进行,如果能转换就自动转换,不能就报错
  2. 显示类型转换:用户自己处理
void test1()
{
    int i = 1;
    // 隐式类型转换
    double d = i;
    printf("%d, %.2f\n" , i, d);
    int* p = &i;
    // 显示的强制类型转换
    int address = (int)p;
    printf("%x, %d\n" , p, address);
}


隐式类型转化有些情况下可能会出问题:

  1. 比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰


2. C++中的类型转换


由于C语言的类型转换的缺陷,C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_castreinterpret_castconst_castdynamic_cast


2.1 static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

用法:static_cast<typename>(variablename);其中typename是将要转换的类型,variablename是要被转换的变量。

void test1()
{
    double d = 12.34;
    int a = static_cast<int>(d);
    int b = d;
    cout<< a << " " << b <<endl;
}


总结:static_cast对标C语言类型转换的隐式类型转换,要求两个类型必须要相关


2.2 reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换 为另一种不同的类型

void test2()
{
    int a = 12;
    //int* p = static_cast<int*>(a);//这里使用static_cast就会报错
    int* p = reinterpret_cast<int*>(a);
    cout << p << endl;
}


总结:reinterpret_cast对标的是C语言的强制类型转换,不要求两个类型是相关类型


2.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

void test3()
{
    const int a = 10;
    //a = 20;//这里由于a是const修饰的变量,所以不能修改
    int* p = const_cast<int*>(&a);
    *p = 20;
    cout << a << " " << *p << endl;
}


拓展知识:如果运行上述的test3代码就会发现,打印出来的a*p的值并不一样,这是什么原因呢?

7ed08e3662407e1662e144e8255aadc4.png

这是因为对于const修饰的变量,编译器会认为它不会被修改,所以会存放在一个寄存器内部,每次访问的时候直接访问寄存器内部的值,所以不会更改。如果想要让他每次都从内存中访问的话,需要加上volatile关键字。

a3bc461e6cf7cb3dc04c18c74bbbbfb3.png


2.4 dynamic

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)

这里补充一下向上转换向下转换的概念:

向上转换:由子类(对象/指针/引用)向父类(对象/指针/引用)的转换

向下转换:由父类(对象/指针/引用)向子类(对象/指针/引用)的转换

其中,向上转换是天然被允许的,中间没有类型转换,也不会产生临时对象,但是向下转换可能会出现数组越界之类的问题,因此是不安全的

class A
{
public:
    virtual void f() {}
    int _a = 1;
};
class B : public A
{
public:
    void f() {}
    int _b = 2;
};
void func(A* ptr)
{
    B* bptr = (B*)ptr;
    cout << bptr->_b << endl;
    cout << bptr->_a << endl;
}
void test4()
{
    A aa;
    B bb;
    func(&aa);
    func(&bb);
}

这里对于A类型的对象,如果要访问_b成员就会出现越界访问的问题。


dynamic_cast的作用就是将一个父类对象的指针/引用转换为子类对象的指针或引用 (向下转型)。需要注意的是:

  • dynamic_cast只能用于父类含有虚函数的类。
  • dynamic_cast会检查是否能转换成功,能则进行转换,不能则返回nullptr。
void func(A* ptr)
{
    //B* bptr = (B*)ptr;
    B* bptr = dynamic_cast<B*>(ptr);
    if(bptr == nullptr)
    {
        cout << "类型转换错误:出现向下转换" << endl;
        return;
    }
    cout << bptr->_b << endl;
    cout << bptr->_a << endl;
}

658970d40fc1fc6f2bb1761552faad9b.png


注意:一般情况下我们应该避免使用强制类型转换,因为强制类型转换关闭或挂起了正常的类型检查;所以每次在使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。


本节完…

相关文章
|
8月前
|
安全 编译器 程序员
【C++】C++的类型转换
【C++】C++的类型转换
|
8月前
|
设计模式 安全 算法
【C/C++ 类型转换 】深入理解C++向上转型:从基础到应用
【C/C++ 类型转换 】深入理解C++向上转型:从基础到应用
247 0
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
127 5
|
8月前
|
存储 安全 编译器
C++:现代类型转换
C++:现代类型转换
60 5
|
3月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
37 1
|
3月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
54 3
|
3月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
62 3
|
3月前
|
C++
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
35 0
|
6月前
|
存储 安全 编译器
【C++11】类型转换
【C++11】类型转换
50 0
|
6月前
|
安全 程序员 编译器
C++一分钟之-C++中的类型转换
【7月更文挑战第8天】C++中的类型转换涉及隐式和显式操作,隐式转换如从`int`到`double`是自动的,但可能导致数据丢失。显式转换包括`static_cast`, `dynamic_cast`, `const_cast`, `reinterpret_cast`,以及转换构造函数。要避免数据丢失、类型不匹配和运行时错误,需谨慎使用显式转换并检查结果。过度使用`reinterpret_cast`应避免。理解这些转换有助于编写更安全的代码。
52 0