• C++类型转换


    类型转换

    隐式类型转换

    显式类型转换

    【1】隐式类型转换

    有些类型转换是自动进行的,不需要人为的介入,比如算术运算时发生的类型转换(int i = 1.0 + 2,double->int),我们称之为隐式的。

    其中场景大概会分为 左值到右值 整型提升 表达式提升 数组到指针 右值到左值 指针与指针 派生类基类

    最详细的资料可参考cppreffrence:https://zh.cppreference.com/w/cpp/language/implicit_conversion 

    具体使用场景(来自C++ primer)

    1. 表达式中,比int类型小的整型值先转换成较大的整数类型(如:short)即:整型提升

    2. 条件中,非布尔值转换为布尔值(如: if(1) ->if(true))

    3. 初始化时,初始值转换为变量的类型

    4. 赋值语句中,右侧运算对象转换成左侧运算对象 (如:int m = 2.0 编译器可能会提示精度损失)

    5. 如果算术运算或者关系运算对象有多种类型,需要先转换成一种类型(并且是最大/宽的那个类型)。(如:int sum = 1.234 + 2)

    6. 数组当作函数传入参数会转换为指针(但是sizeof不会)

    7. 派生类对象可以隐式的转化为基类对象

    8. 指针的转换(0/unllptr 可转为任意指针类型;指向非const的指针可转为 void*;任意对象指针可转为 const void*)

     1     //赋值和算术运算
     2     char c = 'a';
     3     char ch = 20;
     4     int m = 3.0 + c;
     5     bool flag = 100;
     6     long l = 1.0L;
     7     unsigned short us = 2.0 + 3;
        //用typeid().name来输出当前变量类型
    8 cout << typeid(c).name() << endl;//char 9 cout << typeid(ch).name() << endl;//char 10 cout << typeid(us).name() << endl;//usigned short 11 cout << typeid(m).name() << endl;//int 12 cout << typeid(3.0 + 'a').name() << endl;//double 13 cout << typeid(flag).name() << endl;//bool 14 cout << typeid(3 + 'a'*5.0).name() << endl;//int 15 cout << typeid(3 + 'a'*5.0 == l).name() << endl;//bool 16 17 if (m)//转换为bool true 18 cout << "m 转换为 bool型" << endl; 19 20 //指针转换 21 int* p = 0; 22 double* d = nullptr; 23 const void* cvp = nullptr; 24 cvp = d; 25 const int* cip = nullptr; 26 void* vp = 0; 27 vp = p;//这里赋值是无意义的,可以输出一下vp试试,会报错 28 cout << typeid(vp).name() << endl; 29 //vp = cip; 错,不可将const类型指针赋给void* 30 cvp = cip; 31 cout << typeid(cvp).name() << endl;//

    说明:类型转换可能会因为编译器的不同而不同。

    【2】显式转换(强制类型转换)

    老一套的强制类型转换已经过时了,如果你还在用形如 double val  =(double)(express...) / x 的话,你过时了。

    格式:cast-name<type>(express)

    有时候我们需要将对象强制转换为另一种类型(虽然有时候不得不这样做,但本质上很危险

    static_cast:只要不包含底层const就可以用(VS中例外)

    1     int i = 10;
    2     double div = static_cast<double>(i) / 3;
    3     cout << div << endl;
    4 
    5     const int t = 10;
    6     double div2 = static_cast<double>(t) / 3;
    7     cout << div2 << endl;

    const_cast:只用于“去const性质”(顶层/底层const都可以消除)

    1 //2. const_cast<typename>(...)专为const设计,用于消除const属性
    2 const int* cx = &i;
    3 int* dc = const_cast<int*>(cx);//dc - int * 类型

    dynamic_cast:支持运行时类型识别(多态的时候)

    沿着继承层级向上、向下、侧向(同级别类),安全的转换到其他类的指针或引用。

    只有三种使用方式

    dynamic_cast<type *>(...) 用于指针转换

    dynamic_cast<type &>(...) 用于引用转换 

    dynamic_cast<type &&>(...) 用于右值引用的转换

    其中...即表达式的类型必须为type/type的派生类/type公有基类

     即:利用该转换可以进行派生类对象到基类对象、基类对象到派生类对象、不同/相同派生类对象之间的转换

    一些转换规则

     1 #include <iostream>
     2  
     3 struct V {
     4     virtual void f() {};  // 必须为多态以使用运行时检查的 dynamic_cast
     5 };
     6 struct A : virtual V {};
     7 struct B : virtual V {
     8   B(V* v, A* a) {
     9     // 构造中转型(见后述 D 的构造函数中的调用)
    10     dynamic_cast<B*>(v); // 良好定义:v 有类型 V*,B 的 V 基类,产生 B*
    11     dynamic_cast<B*>(a); // 未定义行为:a 有类型 A*,A 非 B 的基类
    12   }
    13     void foo()
    14     { std::cout << "This is inside of B " << std::endl; }
    15 };
    16 struct D : A, B {
    17     D() : B((A*)this, this) { }
    18     void foo()
    19     { std::cout << "This is inside of D " << std::endl; }
    20 };
    21  
    22 struct Base {
    23     virtual ~Base() {}
    24     void foo()
    25     { std::cout << "This is inside of Base " << std::endl; }
    26 };
    27  
    28 struct Derived: Base {
    29     virtual void name() {}
    30     void foo()
    31     { std::cout << "This is inside of Derived " << std::endl; }
    32 };
    33  
    34 int main()
    35 {
    36     D d; // 最终派生对象
    37     A& a = d; // 向上转型,可以用 dynamic_cast,但不必须
    38     D& new_d = dynamic_cast<D&>(a); // 向下转型
    39     new_d.foo();
    40     
    41     B& new_b = dynamic_cast<B&>(a); // 侧向转型
    42     new_b.foo();
    43  
    44     std::cout << "
    the base odject init derived object" << std::endl;
    45     Base* b1 = new Base;
    46     b1->foo();
    47     if(Derived* d = dynamic_cast<Derived*>(b1))//转换失败,到目前为止我还没有搞懂,为什么该种类型的基类指针为什么不能转换为派生类指针。
    48     {
    49         std::cout << "downcast from b1 to d successful
    ";
    50         d->name(); // 可以安全调用
    51         d->foo();
    52     }
    53     else
    54         std::cout << "cast fail" << std::endl;// cast fail
    55  
    56     std::cout << "
    the derived odject init base object" << std::endl;
    57     Base* b2 = new Derived;
    58     b2->foo();
    59     if(Derived* d = dynamic_cast<Derived*>(b2))
    60     {
    61         std::cout << "downcast from b2 to d successful
    ";
    62         d->name(); // 可以安全调用
    63         d->foo();
    64     }
    65     else
    66         std::cout << "cast fail" << std::endl;
    67  
    68     delete b1;
    69     delete b2;
    70 }
    //结果
    This is inside of D 
    This is inside of B 
    
    the base odject init derived object
    This is inside of Base 
    cast fail
    
    the derived odject init base object
    This is inside of Base 
    downcast from b2 to d successful
    This is inside of Derived 
    gcc7.1(C++17)运行结果

    reinterpret_cast:用于重新解释类型(很危险,不建议使用)

    reinterpret_cast<type>(expression) 纯粹是一个编译时指令,它指示编译器将type按照指定的express类型来解释和处理。所以,很危险。

  • 相关阅读:
    Linux下支持mysql支持远程ip访问
    vscode显示php函数列表
    摘:关于php调用.net的web service 踩过的坑
    php接收json格式数据(text/xml)
    php查询快递信息
    php获取客户端ip
    PHP到浏览器的缓存机制
    soap缓存问题
    WordPress For SAE 移植
    使用 AWS CloudTrail 记录 IAM 和 AWS STS API 调用
  • 原文地址:https://www.cnblogs.com/yocichen/p/10596876.html
Copyright © 2020-2023  润新知