美文网首页C/C++程序设计专题学习程序猿学习
C++系列 --- 类型转换:static_cast、reint

C++系列 --- 类型转换:static_cast、reint

作者: 307656af5a04 | 来源:发表于2019-04-23 08:47 被阅读38次

    一、隐式类型转换

    《C++ Primer》中提到:

    “可以用 单个形参来调用 的构造函数定义了从 形参类型该类类型 的一个隐式转换。”

    这里应该注意的是, “可以用单个形参进行调用” 并不是指构造函数只能有一个形参,而是它可以有多个形参,但那些形参都是有默认实参的。

    那么,什么是“隐式转换”呢? 上面这句话也说了,是从 构造函数形参类型该类类型 的一个编译器的自动转换。

    系统自动进行,不需要程序开发人员介入。

    // 45 把小数部分截掉,也属于隐式类型转换的一部分
    int m = 3 + 45.6;
    
    double b = 3 + 45.6; // 45.6
    

    实例:

    #include <string>
    #include <iostream>
    using namespace std;
    
    //定义了一个书类
    class BOOK  
    {
    private:
        string _bookISBN ;  //书的ISBN号
        float _price ;    //书的价格
    
    public:
        //定义了一个成员函数,这个函数
        //即是那个“期待一个实参为类类型的函数”
        //这个函数用于比较两本书的ISBN号是否相同
        bool isSameISBN(const BOOK & other )
        {
            return other._bookISBN==_bookISBN;
        }
    
        //类的构造函数,即那个“能够用一个参数
        // 进行调用的构造函数”(虽然它有两个形参,
        //但其中一个有默认实参,只用一个参数也能进行调用)
        BOOK(string ISBN,float price=0.0f):
            _bookISBN(ISBN),_price(price){}
    };
    
    int main()
    {
        BOOK A("A-A-A");
        BOOK B("B-B-B");
    
        //正经地进行比较,无需发生转换
        cout<<A.isSameISBN(B)<<endl;   
    
        //此处即发生一个隐式转换:string类型-->BOOK类型,
        //借助BOOK的构造函数进行转换,以满足isSameISBN函数的参数。
        cout<<A.isSameISBN(string("A-A-A"))<<endl; 
        
        //显式创建临时对象,也即是编译器干的事情。
        cout<<A.isSameISBN(BOOK("A-A-A"))<<endl;    
        
        system("pause");
        return 0;
    }
    

    代码中可以看到,isSameISBN函数期待的是一个BOOK类类型形参的,但我们却传递了一个string类型的给它,这不是它想要的啊!还好,BOOK类中有个构造函数,它使用一个string类型实参进行调用,编译器调用了这个构造函数,隐式地将stirng类型转换为BOOK类型(构造了一个BOOK临时对象),再传递给isSameISBN函数。

    隐式类类型转换还是会带来风险的,隐式转换得到类的临时变量,完成操作后就消失了,我们构造了一个完成测试后被丢弃的对象。

    我们可以通过explicit声明来抑制这种转换:

    explicit BOOK(string ISBN,float price=0.0f):
        _bookISBN(ISBN),_price(price){}
    

    explicit关键字只能用于类内部的构造函数声明上.这样一来,BOOK类构造函数就不能用于隐式地创造对象了。

    现在用户只能进行显示类型转换,显式地创建临时对象。

    隐式类型转换总结

    • 可以使用一个实参进行调用,不是指构造函数只能有一个形参。

    • 隐式类类型转换容易引起错误,除非你有明确理由使用隐式类类型转换,否则,将可以用一个实参进行调用的构造函数都声明为explicit。

    • explicit只能用于类内部构造函数的声明。它虽然能避免隐式类型转换带来的问题,但需要用户能够显式创建临时对象(对用户提出了要求)

    二、显示类型转换(强制类型转换)

    int key = 5 % 3.2; // 语法错误
    // 强制转换为3,C语言风格的类型转换
    int k   = 5 % (int)3.2; 
    // 函数风格的强制类型转换
    int k1  = 5 % int(3.2); 
    

    C++类型强制类型转换分为4种:

    这四种强制类型转换被称为命名的强制类型转换;目的是为了提供更加丰富的含义和功能,更好的类型检查机制。

    通用形式:强制类型转换名<type>(express)

    (1)static_cast:静态转换,编译的时候就会进行类型转换的检查

    代码中要保证类型转换的安全性与正确性,含义与C语言的强制类型转换意义差不多。C风格的强制类型转换以及编译器能够进行的隐式类型转换,都可以用static_cast类型显示完成。

    可用于:

    (a)相关类型转换,比如整型和实型之间的转换

    double f = 100.43f;
    int i = (int)f; // C风格的
    // C++风格的强制类型转换 显示
    int i2 = static_cast<int>(f); 
    

    (b)子类转换为父类的时候(继承关系),也可以用static_cast

    calss A{};
    class B : public A{}; // 公有继承
    B b;
    // 将子类转换为父类
    A a = static_cast<A>(b);
    

    (c)void *与其他的类型指针之间的转换,void *无类型指针,可以指向任何类型的指针(万能指针)

    int i = 10;
    int *p = &i;
    // int *转换为void *
    void *q = static_cast<void *>(p); 
    // 将void *转换回int *
    int *dq = static_cast<int *>(q);  
    

    一般不能用于:

    (a)一般不能用于指针类型之间的转换比如int * 转double *,float 转 double等等

    double f = 100.0f;
    double *pf = &f;//
    //int *i_f = static_cast<int *>(pf); // 不可以
    //float *f_f = static_cast< float *>(pf); // 不可以
    

    (2)dynamic_cast

    主要应用于运行时类型识别与检查。主要用来父类型和子类型之间转换用(父类型指针指向子类型对象,然后用dynamic_cast把父指针类型转换为子指针类型)

    (3)const_cast

    去除指针或引用的const属性,该指针能将const性质转换掉,编译时类型转换。

    cons tint ai = 90;
    //int ai2 = const_cast<int>(ai); // ai不是指针或引用,不能转换
    const int *pai = &ai;
    const int *pai2 = const_cast<int *>(pai); // 语法正确
    *pai2 = 120; // 这种写值行为,属于一种未定义行为,尽量不要这么写
    cout <<ai << endl; // 90
    cout << *pai << endl; // 120
    
    const int ai = 90;
    int *pai2 = (int *)&ai; // 语法正确
    
    // 这种写值行为,属于一种未定义行为,
    // 尽量不要这么写
    *pai2 = 120; 
    cout << ai << endl; // 90
    cout << *pai2 << endl; // 120
    

    (4)reinterpret_cast

    编译的时候就会进行类型转换的检查,翻译,重新解释

    将操作数内容解释为另一种不同的类型。

    处理无关系的转换,也就是两个类型转换之间没有什么关系;就等于什么都可以转换。

    (a)将一个整型(地址)转换为指针,一种类型指针转换为另一种类指针,按照转换后的内容重新解释内存中的内容。

    (b)也可以从一个指针转换为整型

    int i = 10;
    int *p = &i;
    int *p2 = reinterpret_cast<int *>(&i);
    char *pc = reineterpret_cast<char *>(pi);
    int I = 10;
    int *p = &I;
    void *pvoid = reinterpret_cast<void *>(p);
    int *p1 = reinterpret_cast<int *>(pvoid);
    // 被认为是危险的类型转换
    
    int iv1 = 100;
    // 88亿  十六字节:2 126A 6DC8
    long long lv1 = 8898899400;
    
    // C语言风格 //0X00000064
    int *piv1 = (int *)iv1; 
    
    //0X00000064
    int *piv2 = reinterpret_cast<int *>(iv1);
    
     // OX126A 6DC8 把前面的2丢了,因为piv2是4
    piv2 = reinterpret_cast<int *>(lv1);字节的
    
    // 指针类型转long long
    long long ne = reinterpret_cast<long long>(piv2); 
    // 308964808 十六进制:126A 6DC8
    

    三、总结

    (1)强制类型转换,不建议使用;强制类型转换能够抑制编译器报错。

    (2)了解类型转换符,方便阅读别人代码。

    好了,今天的C++学习到这里就结束了,喜欢的朋友可以给我点个赞哦!!!

    相关文章

      网友评论

        本文标题:C++系列 --- 类型转换:static_cast、reint

        本文链接:https://www.haomeiwen.com/subject/ivrowqtx.html