C++中的类型转换


一、隐式类型转换

 
隐式类型转换,顾名思义,就是没有明显的声明要进行类型转换,隐式类型转换有可能造成数据精度的丢失,所以通常所做的类型转换都是从size小的数据到size大的数据。
 
我们以数字为例,在程序中见到的所有整形立即数都被当作int类型,所有浮点数立即数都被当作double类型,如下所示:

int main() {
    auto a = 12.34;
    auto b = 100;
    std::cout << typeid(a).name() << std::endl; //double
    std::cout << typeid(b).name() << std::endl; //int
    return 0;
}

在进行加减乘除等基本运算的时候,首先要保证运算符两边是同类型的数据,这时候,编译器会做隐式的类型转换,都是将数据从size小转到size大,这时不会损失数据精度,⚠️同时存在signedunsigned的时候,signed会转换成unsigned。其他的转换借鉴下图:
在这里插入图片描述
对象中包含的隐式转换:

  1. 对象构造的时候使用如果编译器可以找到对象的构造函数,此时也会发生隐式的类型转换,但是通常不希望这种情况发生,可以在构造函数前加explicit关键字进行避免;

 

二、显式类型转换

这个没什么好说的,通过类型强转的方式,程序上能直接指定要转换成何种类型。但是需要注意一点的是,对象也能通过运算符重载函数强转成基本类型。使用方法如下:

class A {
public:
    explicit A(int ma) : _ma(ma) {

    }
    explicit operator double() const {
        double a = 13.34;
        return a;
    }
private:
    int _ma;
};

 

三、c++风格的类型转换

  1. static_cast
    static_cast类似于强制类型转换,只是是一种tight type check的类型转换,而且是编译时期的类型转换。之所以说他是tight type check是因为static_cast不允许做一些不合理的类型转换,如下所示:
#include <iostream>
#include <iostream>
using namespace std;
int main()
{
    int a = 10;
    char c = 'a';
  
    // pass at compile time, may fail at run time
    int* q = (int*)&c;  //clang编译通过
    int* p = static_cast<int*>(&c); //编译失败
    return 0;
}

另外在继承结构中,必须是public继承才能使用static_cast进行类型向上转换,如下所示:

class Base {
};

class Derived : private Base { // Inherited private/protected not public
};

int main() {
    Derived d1;
    Base *b1 = (Base *) (&d1); // allowed
    Base *b2 = static_cast<Base *>(&d1); //编译失败
    return 0;
}

 
2. dynamic_cast
这种转换需要用到RTTI机制,关于RTTI的原理和对象内存布局,见我的另一篇博客C++对象内存布局
在这里插入图片描述

既然涉及到RTTI,那就必须有虚函数,如果继承结构中没有虚函数,那也就用不了dynamic_cast,dynamic_cast支持downcasting和upcasting,但是指针必须指向的是同一个对象,如果转换失败,dynamic_cast返回nullptr。使用方法如下:

// C++ program demonstrate if there
// is no virtual function used in
// the Base class
#include <iostream>
using namespace std;

// Base class declaration
class Base {
	void print()
	{
		cout << "Base" << endl;
	}
};

// Derived Class 1 declaration
class Derived1 : public Base {
	void print()
	{
		cout << "Derived1" << endl;
	}
};

// Derived class 2 declaration
class Derived2 : public Base {
	void print()
	{
		cout << "Derived2" << endl;
	}
};

// Driver Code
int main()
{
	Derived1 d1;

	// Base class pointer hold Derived1
	// class object
	Base* bp = dynamic_cast<Base*>(&d1);

	// Dynamic casting
	Derived2* dp2 = dynamic_cast<Derived2*>(bp);
	if (dp2 == nullptr)
		cout << "null" << endl;

	return 0;
}

 
3. reinterpret_cast
顾名思义,重新解释的意思,这种类型转换将任意一种指针转换成另一种指针,这是一种危险的转换,使用方式如下:

#include <iostream>
using namespace std;
 
int main()
{
    int* p = new int(65);
    char* ch = reinterpret_cast<char*>(p);
    cout << *p << endl;
    cout << *ch << endl;
    cout << p << endl;
    cout << ch << endl;
    return 0;
}

 
4. const_cast
const_cast用于将变量的const约束去掉,const_cast并不像想象的那样可以直接修改const变量,const_cast去除掉的一般是指针的约束,使用方法见下:

const int a=10;
int b  = const_cast<int>(a); //这里会编译失败,因为实际上a的const限制是无法去除的
int main(void) {
    int a1 = 40;
    const int *b1 = &a1;
    int *c1 = const_cast <int *> (b1); 
    *c1 = 100;   //此处没有问题,可以通过c1修改a1;
    *b1 = 1000; //此处编译失败,不能通过b1修改a1;
    cout << a1 << endl;
    return 0;
}

如上所示,a1并不是const变量,只是我们定义了一个const指针,我们不能通过这个指针修改a1,但是我们可以把指针的const去掉,然后用去掉const限制的指针来修改a1。
 
const_cast还可以用来在类的const函数中修改成员变量,因为在const方法中的this指针实际上是一个const指针,我们可以用const_cast去掉const限制,然后来修改成员变量,使用方法如下所示:

class student
{
private:
    int roll;
public:
    // constructor
    student(int r):roll(r) {}
  
    // A const function that changes roll with the help of const_cast
    void fun() const
    {
        ( const_cast <student*> (this) )->roll = 5;
    }
  
    int getRoll()  { return roll; }
};

const_cast是一种比强转更安全的类型转换,比如将const int* 转为int是允许的,但是将const int转为char*是不允许的。
const_cast还可以将volatile约束去掉,如下所示:

int main(void)
{
    int a1 = 40;
    const volatile int* b1 = &a1;
    cout << "typeid of b1 " << typeid(b1).name() << '\n'; //PVKi
    int* c1 = const_cast <int *> (b1);
    cout << "typeid of c1 " << typeid(c1).name() << '\n'; //Pi
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值