zoukankan      html  css  js  c++  java
  • C++的类型转换

    C++的类型转换

    类型转换4大金刚:

    • static_cast --- 执行基础转换
    • const_cast ---- (添加或者)移除 const
    • dynamic_cast ---- 执行已检查的多态转换,沿着继承层次结构安全地将指针和引用转换为向上、向下和横向的类
    • reinterpret_cast --- 执行一般的低级转换

    static_cast使用场景

    使用隐式转换和用户定义转换的组合在类型之间进行转换

    语法:
    static_cast < new_type > ( 表达式 )
    返回type的值new_type

    以下总结常使用static_cast的场景

    1. 初始化时转换

    //1.initializing conversion
    	int n = static_cast<int>(3.14159);
    	cout << "n = "<<n<<"
    "; //n=3
    
    	std::vector<int> v = static_cast<std::vector<int>>(10);
    	cout << "size of v is "<<v.size()<<"
    "; //10
    

    打印值在注释中,通过static_cast将某些类型做“静态”转变后成为我们希望的类型,并能正确初始化。

    2. static downcast

    struct B{
        static const int m = 0;
        void hello() const {
        	cout <<"hello ,this is B"<<"
    ";
        }
    };
    
    struct D:B
    {
        void hello() const{
        	cout << "hello,this is D"<<"
    ";
        }
    };
    
    //2. static downcast
        D d;
        B& br = d;
        br.hello(); //hello ,this is B
        D& anther_d = static_cast<D&>(br);
        anther_d.hello();//hello ,this is D
    
    

    br通过隐式类型转换后作为d的引用,虽然d是D类型的,但是调用的hello仍是B的hello函数,使用static_cast显式downcast后,调用D的hello。这里有一个问题是,hello并不是虚函数,即时D继承B,B和D都有一个hello,但是这里的hello函数并不是动态绑定的,仍在编译期绑定this的类型。因此br是B类型,而anther_d是D类型的(这里有疑问!!?)
    如果hello是虚函数,那么怎么解释呢?

    3. 隐式转换翻转

     	void* nv = &n;
        int* ni = static_cast<int*>(nv);
        std::cout << "*ni = " << *ni << '
    ';
    

    这算是static_cast 最常用的用法了,通过void指针将类型反转赋值。void可以通过static_cast转变为任意指针类型。

    4. enum类型转换

    enum E{ONE = 1,TWO,THREE};
    E e = E::ONE;
    int one = static_cast<int>(e);
    cout << "one : "<<one <<"
    ";
    

    const_cast使用场景

    1. 一般的const移除

    int i = 4;
    const int& rci = i ;
    const_cast<int&>(rci) = 8;
    
    const int j = 33;
    int*pj = const_cast<int*>(&j);
    //DO not use like below !
    // *pj = 333;
    // cout << "const int j = "<< j <<"
    ";
    

    2. 在类的const成员函数中:

    struct type{
        int i ;
    
        type() :i(3){}
        void f(int v) const{
    	//if we want to modify i 
    	//we cannot use this->i = v; directly;
    	//becuse this pointer is const ,
    	//we shall use const_cast this pointer
    	const_cast<type*>(this)->i = v;
        }
    };
    
    type t;
    t.f(40) ;
    cout << "type i = "<<t.i <<"
    ";
    
    

    使用const修饰的成员函数,我们将无法通过this指针,修改其成员变量,因为我们可以将this指针使用const_cast转换为non-const的,只是,你真的确定要这么做么?!

    dynamic_cast 使用场景

    必须是多态场景,存在基类与派生类的类型转换;如果转换成功,dynamic_cast返回类型为new_type的值。如果转换失败,而new_type是指针类型,则返回该类型的空指针。如果转换失败,并且new_type是引用类型,它将抛出一个异常,该异常与类型std::bad_cast的处理程序匹配。

    struct Base {
        virtual ~Base() {}
    };
     
    struct Derived: Base {
        virtual void name() {}
    };
    
    void testDynamic_cast()
    {
        Base *b1 = new Base;
        if(Derived*d = dynamic_cast<Derived*>(b1)){
            cout << "downcast from b1 to d successful
    ";
            d->name();
        }
    
        Base *b2 = new Derived;
        if(Derived*d = dynamic_cast<Derived*>(b2)){
            cout << "downcast from b2 to d successful
    ";
            d->name();
        }
    
        delete b1;
        delete b2;
    }
    

    输出
    downcast from b2 to d successful

    可见b1的dynamic_cast转换是失败的。原因是显而易见的 ,此时的b1指针并没有指向其派生类,自然不能进行动态转换。但是,在C类型的转换中,这样的转换是没有任何提示和预见性的,所以,C类型的转换应该被全线禁止掉。

    reinterpret_cast的使用场景

    标准文档上的解释是:通过重新解释底层位模式在类型之间进行转换

    与static_cast不同,但与const_cast相似,reinterpret_cast表达式不会编译成任何CPU指令(除非在整数和指针之间进行转换,或者在指针表示依赖于其类型的模糊架构上进行转换)。

    它纯粹是一个编译时指令,指示编译器将表达式视为具有new_type类型

    unsigned int i = 0x12345678;
    
    char* p1 = reinterpret_cast<char*>(&i);
    if(p1[0] == 'x78')
    	cout << "This system is little-endian
    ";
    else 
    	cout << "This system is big-endian
    ";
    

    p1指针将i的地址重现解释为char*类型。这里顺便复习下大小端的知识,78是i的低字节位,如果它位于unsigned int内存的低地址区域则说明系统为小端,否则为大端。

    以上,说明了四种C++类型转换表达式的使用场景,按我个人理解小结下:

    • 如果希望在内存指针层面对指针重新解释,也是就让编译器认为这个指针是某个类型,则需要使用reinterpret_cast,
    • 如果涉及到基类和派生类指针的动态转换,则使用dynamic_cast;
    • 如果需要移除const属性,则需要使用const_cast;
    • 其余情况就使用static_cast吧。
  • 相关阅读:
    AtCoder Grand Contest 015 题解
    AtCoder Grand Contest 014 题解
    AtCoder Grand Contest 013 题解
    AtCoder Grand Contest 012 题解
    AtCoder Grand Contest 011 题解
    AtCoder Grand Contest 010 题解
    AtCoder Grand Contest 009 题解
    NOIP2017 Day2 题解
    博客园主题备份
    多项式全家桶
  • 原文地址:https://www.cnblogs.com/Stultz-Lee/p/10089087.html
Copyright © 2011-2022 走看看