【C++】类型转换

在C++中,类型转换(Type Conversion)是将一种数据类型转换为另一种数据类型的过程。类型转换可以分为两大类:隐式转换(implicit conversion)和显式转换(explicit conversion)。

1. 隐式转换

隐式转换是由编译器自动完成的,不需要显式的类型转换操作符。这种比较简单。常见的隐式转换有以下几种:

1.1 整形提升

charshort 等较小的整数类型可以自动提升为 int

char c = 'A';
int i = c;  // char 自动提升为 int

1.2 算术转换

不同类型的数据在混合运算时会进行转换,以确保运算的正确性。例如,intdouble 进行运算时,int 会被转换为 double

int i = 10;
double d = 3.14;
double result = i + d;  // int 被转换为 double

2. 显示转换

以上都属于C风格的转换格式,简单但是有一些问题,

  • 隐式类型转化有些情况下可能会出问题:比如数据精度丢失。
  • 显式类型转换将所有情况混合在一起,代码不够清晰。

因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:

  • static_cast
  • reinterpret_cast
  • const_cast
  • dynamic_cast

2.1 static_cast

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

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);//将d转换为ind
	std::cout << a << std::endl;//输出12
	return 0;
}

两个不相关的类进行转换,会出错。如下:

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);//将d转化为int
	std::cout << a << std::endl;//输出12
	int* p = static_cast<int*>(a);//将a转化为int*类型 error
	return 0;
}

2.2 reinterpret_cast

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

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);//将d转化为int
	std::cout << a << std::endl;//输出12
	//int* p = static_cast<int*>(a);//将a转化为int*类型
	int* p = reinterpret_cast<int*>(a);//将a转化为int*类型

	return 0;
}

reinterpret_cast不进行任何类型安全检查,因此可能会导致未定义行为。它只改变对象的解释方式而不改变对象的存储内容。应尽量减少使用。

2.3 const_cast

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

int main()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 3;
	std::cout << a << std::endl;
	std::cout << *p << std::endl;
	return 0;
}

注意:在C++标准中,试图修改一个 const 对象的值会导致未定义行为。这意味着编译器对这个操作不会进行任何保障,程序的结果可能是不确定的,可能导致崩溃、不可预期的输出,甚至可能在不同的编译器或平台上表现出不同的行为。

上面的代码运行结果:

ee536e9d160ee0b873a0230dbf67e3c.png
内存中存放的是3,但是打印显示的是2。

这种属于未定义行为,未定义行为(Undefined Behavior, UB)是指程序的行为没有明确定义的情况,这意味着编译器对代码的行为没有任何规定,程序可以表现出任何结果。会导致程序崩溃红藕这生成错误的结果,看似正常但潜在有安全隐患。应该理解并避免未定义行为。

2.4 dynamic_cast

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

子类转父类 直接转就行了~ 不需要转换,赋值兼容规则。

  • dynamic_cast只能用于父类含有虚函数的类。
  • dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。
//父类Base
class Base
{
public:
    Base() = default;
    Base(const Base& b) = default;
    virtual ~Base() = default;

    void show()
    {
        std::cout << "Hello Base" << std::endl;
    }
};

//子类Drivaer
class Drivaer : public Base
{
public:
    Drivaer()
        :Base()
    {

    }

    void show()
    {
        std::cout << "Hello Drivaer" << std::endl;
    }
};

int main()
{
    Base* b = new Base;
    Drivaer* d = new Drivaer;

    //将父类指针b转换为子类指针类型
    if (Drivaer* bb1 = dynamic_cast<Drivaer*>(b))
    {
        bb1->show();
    }
    else
    {
        std::cout << "dynamic_cast fail" << std::endl;
    }
    
    
    if (Drivaer* bb2 = static_cast<Drivaer*>(b))
    {
        bb2->show();
    }
    else
    {
        std::cout << "static_cast fail" << std::endl;
    }

}

上面程序运行结果:

image.png

  • 使用dynamic_cast转换失败

因为 b 指向的是 Base 类对象,dynamic_cast 返回 nullptr。在使用 dynamic_cast 进行类型转换时,如果转换不安全(即基类指针指向的对象不是目标派生类的对象),dynamic_cast 将返回 nullptr

必须让父类指针指向子类的对象才可以转换成功。

image.png

  • static_cast转换成功

static_cast 允许将指针或引用从一个类型转换为另一个相关类型,但不会进行运行时类型检查。因此,如果 static_cast 用于将父类指针或引用转换为子类指针或引用,可能会导致未定义行为(如访问不存在的派生类成员或对象切片问题)。

3. 总结

在 C++ 中,显示转换(Explicit Type Conversion)是通过使用不同的类型转换操作符来实现的,每种操作符都有其特定的用途和适用条件。

  • static_cast

    • 用于编译时类型转换。
    • 支持较宽泛的转换,如整数之间的类型转换、相关类型的指针或引用转换(但不涉及底层 const 属性的转换)、向上和向下的类层次转换(但不进行运行时类型检查)。可能引发未定义行为,慎用。
    • 不能用于在不相关的类之间进行转换。
  • reinterpret_cast

    • 用于将一个指针转换为另一个类型的指针,或者将一个指针转换为一个整数类型,反之亦然。
    • 非常危险,潜在地引入未定义行为。
    • 主要用于低级编程和与硬件相关的编程场景。
  • const_cast

    • 用于移除对象的 constvolatile 修饰
    • 主要用于在函数中修改传入参数的 const 属性。
    • 如果使用 const_cast 来修改一个原本声明为 const 的对象,而该对象实际上是 const 的(例如通过字面常量或者通过 const 对象的指针进行转换),则会导致未定义行为。慎用。
  • dynamic_cast

    • 用于运行时类型检查,主要用于类层次间的安全向下转型(Downcasting)
    • 只能用于含有虚函数的类(多态类型)。
    • 如果转换不安全,返回 nullptr(对于指针)或抛出 bad_cast 异常(对于引用)。

总的来说,要避免未定义行为,应当遵循以下原则:

  • 尽量避免使用 reinterpret_cast,除非绝对必要且非常清楚其风险。
  • 在使用 const_cast 时,确保转换是安全的,并且不会尝试修改本来应该是 const 的对象。
  • 使用 static_castdynamic_cast 时,确保类型之间有合理的转换关系,并避免不相关类型之间的转换。父类转子类安安全全使用dynamic_cast
  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++下等马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值