• C++:显式和隐式初始化、显式和隐式类型转换


    C++中显式初始化、隐式初始化;显式转换、隐式转换;是几个容易混淆的概念,在实际应用中经常容易出错,下面就把他们归纳一下,和大家分享。
    1.   显式和隐式初始化

    有一个类的构造函数为: A(int i) : m_i(i){}

    1.1 C++显式初始化

    内置类型: int ival = 1024; string hello = "Hello world."

    自定义类型的显式初始化:

    A abc(200);  //显式初始化,直接调用构造函数

    A a = A(1);   //直接调用构造函数,没有临时对象,作用域结束时析构

    A* e = new A(2);        //直接调用构造函数,使用delete时析构

    A d(*e);         //显式初始化,调用拷贝构造函数,作用域结束时析构

    1.2 C++隐式初始化

    内置类型: int ival(1024); string hello("Hello world.")

    自定义类型的隐式初始化:

    A c = 0;         //这是一种隐式初始化,直接调用构造函数,没有临时对象。不要看到=号就以为要用拷贝构造函数。

    A b = a;        //用一个对象隐式初始化另一对象,调用拷贝构造函数,作用域结束时析构

    1.3 赋值操作符: 对已初始化了的对象赋值,用赋值操作符。如果是声明的同时为对象赋值,则调用构造函数或者拷贝构造函数。

    A a(1);          //显式初始化

    a = 10;         //调用构造函数构造一临时对象,调用赋值函数,赋值后临时对象马上被析构

     

    2. 隐式和显式类型转换.

    2.1 隐式类型转换

    2.1.1 C++隐式转换发生在四种情况下:(混合运算,赋值,传参,返回值)

                 1)在混合类型的算术表达式中

    int ival = 3;

    double dval = 3.1415;

    ival + dval; //ival 被提升为double 类型:3.0

                 2)用一种类型的表达式赋值

    int *pi = NULL;   // NULL(0)被转换成了int* 类型的空指针值

                 3)用一个表达式传递给一个函数调用

    extern double sqrt(double);

    sqrt(2);        //2被提升为double类型: 2.0

    4)从一个函数返回一个表达式

    double difference(int ival1, int ival2) { return ival1 - ival2; //返回值被提升为double 类型. }

    2.1.2内建类型对像之间默认隐式转换 C++内建类型(char,int,short,double etc.)对像之间默认含有隐式转换

    2.1.3用户定义类对象之间可以含有隐式转换 C++用户定义类对象之间可以含有隐式转换.

    void dosomething(A aObject);

    class A { public: A(int x = 0); }

    dosomething(20);     // Ok 隐式转换,如用explicit修饰构造函数,则不能隐式转换。

     

          2.2 显式类型转换

    C++显式转换包含四种转换

    static_cast : 编译期的转化,不能转换掉表达式的const、volitale、或者__unaligned属性

    *所有内建类型对象之间的隐式转换都可用static_cast.

    *把空指针转换成目标类型的空指针用static_cast。

    *把任何类型的表达式转换成void类型用static_cast。

    *类层次间的上行转换和下行转换也可以用static_cast,但下行转换即当把基类指针或引用转换成子类表示时,由于没有动态类型检查,所以是不安全的.反之是安全的.

    dynamic_cast : 运行期的转换,类层次间的上行转换和下行转换

    *dynamic_cast具有类型检查的功能,上行转换的效果跟static_cast是一样的,但下行转换比static_cast更安全。

    *dynamic_cast还支持交叉转换,两个类如果有共同的祖先,他们的指针就可以用dynamic_cast.

    const_cast : 编译期的转化,类型中的常量,该运算符用来修改类型的const或volatile属性。

                   一、常量指针被转化成非常量指针,并且仍然指向原来的对象;

    二、常量引用被转换成非常量引用,并且仍然指向原来的对象;

                   三、常量对象被转换成非常量对象。

    reinterpret_cast : 任何指针都可以转换成其它类型的指针,可用于如char* 到 int*,或者One_class* 到 Unrelated_class* 等的转换,因此可能是不安全的。

     

    2.3内建类型指针之间不含有隐式转换(void * 除外)

    C++内建类型指针之间不含有隐式转换(void * 除外),需要显式转换。

    int ival = 0;

    char* pc = NULL;

    int* pi = NULL;

    void* pv = NULL;

    const char* pcc = "Hello world";

    const int* pci = &ival;

    const void* pcv = NULL;

    pc = pi; //错误,没有标准的隐式转换.

    pc = reinterpret_cast(pi); //必须使用reinterpret_cast 在位模式层次的显式转换

    pc = pv;                            //错误,没有标准的隐式转换.

    pc = static_cast(pv);          //static_cast显式转换

    pc = pcc;                          //错误,没有标准的隐式转换.

    pc = const_cast(pcc);       //const_cast显式转换

    pc = pcv;                          //错误,没有标准的隐式转换.

    pc = static_cast(const_cast(pcv)); //先const_cast 后 static_cast.

    pv = pc;              // OK; 隐式转换到void*

    pv = pi;               // OK; 隐式转换到void*

    pv = pcc;            //错误,没有标准的隐式转换.

    pv = const_cast(pcc); //OK, const_cast显式转换,并且char* 隐式转换到void*

    pv = pcv;             //错误,没有标准的隐式转换.

    pv = const_cast(pcv);        //OK, const_cast显式转换.

    pcc = pc;            // OK; 隐式转换到const char*

    pcc = pi;             // 错误,没有标准的隐式转换.

    pcc = reinterpret_cast(pi);      //必须使用reinterpret_cast 在位模式层次的显式转换.

    pcc = pv;     // 错误,没有标准的隐式转换.

    pcc = static_cast(pv);       //static_cast显式转换

    pcc = pci;     // 错误,没有标准的隐式转换.

    pcc = reinterpret_cast(pci); //必须使用reinterpret_cast 在位模式层次的显式转换.

    pcc = pcv;           //错误,没有标准的隐式转换.

    pcc = static_cast(pcv);     //static_cast显式转换.

    pcv = pv;      // OK; 隐式转换到const void*

    pcv = pc;     // OK; 隐式转换到const void*

    pcv = pi;      // OK; 隐式转换到const void*

    pcv = pcc;    // OK; 隐式转换到const void*

     

          2.4显式转换可以消除不必要的提升

    double dval;

    int ival;

    ival += dval; 这段赋值,首先将ival提升到double型,然后与dval相加,得到结果再截取成int. 通过显式转换,消除ival 从int型到double型的不必要提升. ival += static_cast(dval);

          2.5 C++用户定义对象之间可以禁止隐式转换

    void dosomething(A aObject);

    class A { public: explicit A(int x = 0); }

    dosomething(20);     // ERROR 隐式转换被禁止.

    dosomething(static_cast(20));      // OK 显式转换. 被声明为explicit 的构造函数通常比non-explicit更好,只有一个参数的构造函数才声明为explicit.

     

    2.6总结

    综合起来说C++ 中应该尽量不使用转换,尽量使用显式转换来代替隐式转换. 尽量不用reinterper_cast 显式转换。

  • 相关阅读:
    Boost.Bind的基础使用
    boost::bind
    winform多线程方式登录代码整理
    shared_from_this 几个值得注意的地方
    [转]gtest使用
    以boost::function和boost:bind取代虚函数
    asio学习2: TCP服务器端:对准时间 解析
    boost asio study
    Asio学习1: TCP客户端:对准时间 解析
    Shawn,别让我们失望
  • 原文地址:https://www.cnblogs.com/reynold/p/2282640.html
Copyright © 2020-2023  润新知