【C++】类型转换


c语音的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与
接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型
转换和显式类型转换。

void Test ()
{
     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);
}

C风格的转换格式很简单,但是有不少缺点的:

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

c++的类型转换

C++ 中有四种类型转换运算符,用于安全、明确地进行不同类型之间的转换。它们分别是:

  1. static_cast
    用于大多数显式转换,适合进行普通的类型转换(如基本数据类型转换、类层次结构中的上行转换)。编译时检查转换是否合理。
   int i = 10;
   double d = static_cast<double>(i); // int 转 double
  1. dynamic_cast
    用于将基类指针或引用安全地转换为派生类类型,只能在多态类(包含虚函数的类)之间转换。转换失败时返回 nullptr(指针)或抛出异常(引用)。
   Base* basePtr = new Derived();
   Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 安全转换,失败时返回 nullptr
	
   Base* basePtr = new Based();
   Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 失败转换,返回 nullptr
  1. const_cast
    用于添加或移除变量的 constvolatile 属性,但不能用于改变类型。通常用于需要传递 const 修饰符的参数。
   const int x = 42;
   int& y = const_cast<int&>(x); // 移除 const 限定符
  1. reinterpret_cast
    用于任意指针类型之间的转换,提供低级别的位模式转换。通常在特定情况下使用,可能带来安全隐患。
   int i = 65;
   char* c = reinterpret_cast<char*>(&i); // 将 int* 转换为 char*

   Base* basePtr = new Based();
   Derived* derivedPtr = reinterpret_cast<Derived*>(basePtr); // 成功转换,有安全隐患

这四种转换方式提供了强类型检查的转换机制,分别适用于不同场景,避免了 C 风格转换的隐患。

RTTI

RTTI(Run-Time Type Information)是 C++ 中的一项机制,允许程序在运行时获取对象的类型信息。RTTI 使得你可以查询对象的动态类型(即对象在运行时的实际类型),并在多态的情况下执行类型转换。

  1. 类型识别
    RTTI 允许你在运行时检查对象的实际类型,特别是在使用基类指针或引用时。通过 typeid 操作符,可以获取对象的类型信息。

    class Base {
    public:
        virtual ~Base() {}  // 有虚函数的基类,启用RTTI
    };
    
    class Derived : public Base {};
    
    Base* basePtr = new Derived();
    std::cout << typeid(*basePtr).name() << std::endl;  // 输出 Derived 类型的名称
    
  2. typeid 操作符
    typeid 用于获取对象的类型信息。它返回一个 std::type_info 对象,可以用于比较类型或获取类型的名字。

    Base* basePtr = new Derived();
    if (typeid(*basePtr) == typeid(Derived)) {
        std::cout << "It is a Derived object." << std::endl;
    }
    
  3. 动态类型转换 (dynamic_cast)
    dynamic_cast 在多态情况下提供安全的转换,特别是将基类指针或引用转换为派生类指针或引用。若转换失败,dynamic_cast 会返回 nullptr(对于指针)或者抛出 std::bad_cast 异常(对于引用)。这种机制依赖于 RTTI。

    Base* basePtr = new Derived();
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
    if (derivedPtr) {
        // 安全转换成功
    }
    

启用 RTTI
RTTI 需要类中至少有一个虚函数来启用。在 C++ 中,虚函数表(vtable)与 RTTI 密切相关,因此只有包含虚函数的类才能启用 RTTI。编译器通过生成虚函数表来实现动态绑定和类型信息的存储。

禁用 RTTI
某些情况下,程序员可能会选择禁用 RTTI,以减少代码的大小或提升性能。在 GCC 和 Clang 编译器中,可以通过 -fno-rtti 标志来禁用 RTTI。禁用 RTTI 后,你将无法使用 typeiddynamic_cast 等功能。

decltype

decltype是c++11新增,有人说他也是RTTI,这不对。

decltype 不属于 RTTI 的一部分。因为 decltype 是在 编译时 确定类型,而 RTTI 是用于 运行时 类型识别。RTTI 依赖于虚函数机制和 typeiddynamic_cast 等关键字来在程序运行时确定对象的实际类型,而 decltype 不需要这些机制,完全在编译期完成类型推导。

可以记住这样一个区别:

  • RTTI:用于运行时的类型检查和转换,例如在多态层次中用 dynamic_cast 进行类型安全的指针转换。
  • decltype:编译时的类型推导,与运行时无关,主要是让编译器在代码生成阶段推导出表达式的类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值