c++隐式类型转换_c++ 隐式类型转换和显示类型转换 - CSDN
精华内容
参与话题
  • c++ 隐式类型转换

    千次阅读 2018-12-25 17:14:32
    文章目录谈谈c++隐式类型转换列举一些隐式类型转换的例子有时候隐式类型转换并不好explic关键词的用法总结 谈谈c++隐式类型转换 什么是c++隐式类型转换?这是指c++自动将一种类型转换成另一种类型,是编译器的一种...

    谈谈c++隐式类型转换

    • 什么是c++隐式类型转换?这是指c++自动将一种类型转换成另一种类型,是编译器的一种自主行为。
    • 为什么c++需要隐式类型转换?
      1. c++多态的特性,就是通过父类的对象实现对子类的封装,以父类的类型返回之类对象。
      2. c++中使用父类的地方一定可以使用子类代替,这也得益于隐式类型转换。
      3. c++是一种强类型的语言,有着非常严格的类型检查,采用隐式类型转换会使程序员更方便快捷一点。
      4. 但是在享受方便的时候,风险也紧跟其后。

    列举一些隐式类型转换的例子

    int i=3;
    double j = 3.1;
    i+j;//i会被转换成double类型,然后才做加法运算。
    
    class A{};
    class B: public A
    {};//B是子类
    void Fun(A& a);
    B b;
    Fun(b);//使用子类对象代替父类对象是可以的,也是因为隐式类型转换。
    

    有时候隐式类型转换并不好

    class Test
    {
    	public:
    		Test(int i);
    };
    
    Test t1 = 1;//正确,由于强制类型转换,1先被Test构造函数构造成Test对象,然后才被赋值给t1
    Test t2(1);//正确
    
    1. 这种情况有时候很好,如果程序员的本意就是如此,那可以省去好几行代码。
    2. 有时这种情况看起来就不那么好,可能是一个错误,程序员错误的写出了这行代码,但是它却奇迹般的没有导致错误,要是因此产生一个bug,那么将是灾难性的。
    3. 为了更准确的表达程序员的自我意愿,本着不怕多写几行代码的心,就使用c++ explicit关键词
    • 再比如有函数用到Test类
    void fun(Test& t);
    fun(1);//这样调用是没有问题的,隐式类型转换会把1转换成Test的对象。
    

    explic关键词的用法

    class Test
    {
    	public:
    		explicit Test(int i);
    };
    Test t2 = 1;//编译报错
    Test t2(2);//编译没问题
    

    总结

    • 隐式类型转换,是编译器自发的行为,所以安全是第一位。所以呢,我们可以得出一条很重要的结论:
      1. 隐式类型转换是从小到大的转换。在数据类型上表现是少字节数据类型,转换成多字节数据类型,保证数据的完整性;在类上表现,从子类转换成父类,保证类对象功能的正常。
      2. 隐式类型转换往往是安全的,但是它可能产生意想不到的危险。
    • 既然有隐式类型转换,那么肯定就有强制类型转换。既然是强制的,那么我们可以猜测一下几点:
      1. 强制类型转换,往往是不安全的,这点要使用者去把握,去了解这种使用是不是安全。
        2. 强制类型转换又是强大的,只要你能保证做的转换的正确性,那么它就是好用的。
    • 强制类型转换和隐式类型转换,我们不能片面的看待他们是不是安全的。存在即合理,安不安全还是要看程序员自己在使用上是否正确,是否合理。
    展开全文
  • 在我们学习c语言的时候,就知道强制类型转换隐式类型转换,但是在类型转换的过程中,很有可能一个不注意,容易出问题,这无疑是加大了,程序员的工作量,而且还检查很不好检查。 所以在c++ 中就对类型转换做...

    在我们学习c语言的时候,就知道强制类型转换和隐式类型的转换,但是在类型转换的过程中,很有可能一个不注意,容易出问题,这无疑是加大了,程序员的工作量,而且还检查很不好检查。

    所以在c++ 中就对类型的转换做了一定的限制,但是实际中大多数人,是在学习了c 语言后才学习 c++ 语言所以就用了 c 语言中的类型转换方式,那么今天我们介绍一下 c++ 中类型转换的方式,他们都是通过类模板的方式实现

    const_cast 把const强转成非const修饰

    在 c 语言中强转是可以把一个不想关的类型都可以强转,但是这样就很容易出问题,如果我们用了const_cast 如果要把两个两个不相关的类型的const转到非const是不行的。这样就限制了出错的概率,,增强了代码的可读性,但是实际中,大多数还是喜欢采用c语言,但是我们必须得知道。

        const int i = 10;//在c++中这样编译器会优化为寄存器变量用volatile
        int* j = const_cast<int*>(&i); // const 与非 const 转换

    static_cast 隐式类型转换

    什么是隐式类型的转换,隐式类型转换,就像c语言中我们可以把一个整型 int 赋值给一个 float 这就是隐式类型的转换。
    我们简单的写一个例子

    void test()
    {
        int i = 10;
        float j = i; // 在c语言中的隐式类型的转换
    
        // 用static_cast转换
        float j = static_cast<float>(i); 
    }

    这样写增强了代码的可读性

    reinterpret_cast 不相关类型转换

    这强制类型转换是就像 c语言中的强转。
    我们举一个例子:

    typedef void (* FUNC)();
    int DoSomething (int i)
    {
    cout<<"DoSomething" <<endl;
    return 0;
    }
    void Test ()
    {
    //
    // reinterpret_cast可以编译器以FUNC的定义方式去看待 DoSomething函// C++不保证所有的函数指针都被一样的使用,所以这样用有时会产生不
    确定的结果
    //
    FUNC f = reinterpret_cast< FUNC>(DoSomething );
    f(); 
    }

    这样我们就把一个函数赋值,还可以调用。

    dynamic_cast虚函数中的父类赋给子类的转化

    dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用(动态
    转换)
    向上转型:子类对象指针->父类指针/引用(不需要转换)
    向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)

    这里用这种强转必须要虚函数的类,用dynamic_cast来转换父类付给子类的时候,有时候可以,有时候不行,这样用dynamic_cast 强转就会在转变的过程中去判断,如果可以把父类给子类就强转,如果不行就返回0.

    class A
    {
        public :
        virtual void f(){}
    };
    class B : public A
    {};
    void fun (A* pa)
    {
        // dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
        B* pb1 = static_cast<B*>(pa);
        B* pb2 = dynamic_cast<B*>(pa);
        cout<<"pb1:" <<pb1<< endl;
        cout<<"pb2:" <<pb2<< endl;
    }
    int main ()
    {
        A a;
        B b;
        fun(&a);
        fun(&b);
        return 0;
    }

    强转
    红色标记的是强转失败,因为把父类赋给子类失败。强转就会判断是否成功。
    如果用c语言中强转可以成功,但是如果强转后,去访问有可能会访问越界。

    explicit关键字

    在强转中,对于单参数的构造函数,支持隐式类型的转换,所以当我们不需要隐式类型的转换的时候,我们就可以加上explicit关键字来防止,在构造函数的时候发生隐式类型的转换。
    单参数的类构造函数的隐式类型转换。

    class A
    {
    public :
        explicit A (int a)
        {
        cout<<"A(int a)" <<endl;
        }
        A(const A& a)
        {
        cout<<"A(const A& a)" <<endl;
        }
    private :
        int _a ;
    };
    int main ()
    {
        A a1 (1);
        // 隐式转换-> A tmp(1); A a2(tmp);
        A a2 = 1; // 这是因为单参数支持隐式类型转换
    }

    我们加上关键字后,用 = 来进行隐式类型转换,是编译不能通过的。
    编译不通过
    如果我们不加就可以通过。

    展开全文
  • 1) 算术转换(Arithmetic conversion) : 在混合类型的算术表达式中, 最宽的数据类型成为目标转换类型。 intival=3; doubledval=3.14159; ival+dval;//ival被提升为double类型 2)一种类型表达式赋值给另一种类型的...

     

    第1部分. 隐式类型转换


    又称为“标准转换”,包括以下几种情况:
    1) 算术转换(Arithmetic conversion) : 在混合类型的算术表达式中, 最宽的数据类型成为目标转换类型。

    int ival = 3;
    double dval = 3.14159;
    
    ival + dval;//ival被提升为double类型

    2)一种类型表达式赋值给另一种类型的对象:目标类型是被赋值对象的类型

    int *pi = 0; // 0被转化为int *类型
    ival = dval; // double->int

    例外:void指针赋值给其他指定类型指针时,不存在标准转换,编译出错

    3)将一个表达式作为实参传递给函数调用,此时形参和实参类型不一致:目标转换类型为形参的类型

    extern double sqrt(double);

    cout << "The square root of 2 is " << sqrt(2) << endl;
    //2被提升为double类型:2.0

    4)从一个函数返回一个表达式,表达式类型与返回类型不一致:目标转换类型为函数的返回类型

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

     

    第2部分. 显式类型转换


    被称为“强制类型转换”(cast)
    C     风格: (type-id)
    C++风格: static_castdynamic_castreinterpret_cast、和const_cast..

     

    关于强制类型转换的问题,很多书都讨论过,写的最详细的是C++ 之父的《C++ 的设计和演化》。最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_cast, dynamic_cast。标准C++中有四个类型转换符:static_castdynamic_castreinterpret_cast、和const_cast。下面对它们一一进行介绍。
     

    static_cast

     

    用法:static_cast < type-id > ( expression )

     

    说明:该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。

     

    来源:为什么需要static_cast强制转换?
    情况1:void指针->其他类型指针
    情况2:改变通常的标准转换
    情况3:避免出现可能多种转换的歧义




    它主要有如下几种用法:
    • 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
    • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
    • 把void指针转换成目标类型的指针(不安全!!)
    • 把任何类型的表达式转换成void类型。
    注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。
     

    dynamic_cast

     

    用法:dynamic_cast < type-id > ( expression )

     

    说明:该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。


    来源:为什么需要dynamic_cast强制转换?
    简单的说,当无法使用virtual函数的时候

    典型案例:
    Wicrosoft公司提供给我们一个类库,其中提供一个类Employee.以头文件Eemployee.h和类库.lib分发给用户
    显然我们并无法得到类的实现的源代码
    //Emplyee.h
    class Employee 
    {
    public:
        virtual int salary();
    };
    
    class Manager : public Employee
    {
    public: 
        int salary();
    };
    
    class Programmer : public Employee
    {
    public:
        int salary();
    };

    我们公司在开发的时候建立有如下类:
    class MyCompany
    {
    public:
        void payroll(Employee *pe);
        //
    };
    
    void MyCompany::payroll(Employee *pe)
    {
        //do something
    }

    但是开发到后期,我们希望能增加一个bonus()的成员函数到W$公司提供的类层次中。
    假设我们知道源代码的情况下,很简单,增加虚函数:
    //Emplyee.h
    class Employee 
    {
    public:
        virtual int salary();
        virtual int bonus();
    };
    
    class Manager : public Employee
    {
    public: 
        int salary();
    };
    
    class Programmer : public Employee
    {
    public:
        int salary();
        int bonus();
    };
    
    //Emplyee.cpp
    
    int Programmer::bonus()
    {
        //
    }
    
    
    payroll()通过多态来调用bonus()
    class MyCompany
    {
    public:
        void payroll(Employee *pe);
        //
    };
    
    void MyCompany::payroll(Employee *pe)
    {
        //do something
        //pe->bonus();
    }

    但是现在情况是,我们并不能修改源代码,怎么办?dynamic_cast华丽登场了!
    在Employee.h中增加bonus()声明,在另一个地方定义此函数,修改调用函数payroll().重新编译,ok

     

    //Emplyee.h
    class Employee 
    {
    public:
        virtual int salary();
    };
    
    class Manager : public Employee
    {
    public: 
        int salary();
    };
    
    class Programmer : public Employee
    {
    public:
        int salary();
        int bonus();//直接在这里扩展
    };
    
    //somewhere.cpp
    
    int Programmer::bonus()
    {
        //define
    }
    
     
    class MyCompany
    {
    public:
        void payroll(Employee *pe);
        //
    };
    
    void MyCompany::payroll(Employee *pe)
    {
        Programmer *pm = dynamic_cast<Programmer *>(pe);
        
        //如果pe实际指向一个Programmer对象,dynamic_cast成功,并且开始指向Programmer对象起始处
        if(pm)
        {
            //call Programmer::bonus()
        }
        //如果pe不是实际指向Programmer对象,dynamic_cast失败,并且pm = 0
        else
        {
            //use Employee member functions
        }
    }
    
    

    dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

    在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
    class Base
    {
    public:
        int m_iNum;
        virtual void foo();
    };
    
    class Derived:public Base
    {
    public:
        char *m_szName[100];
    };
    
    void func(Base *pb)
    {
        Derived *pd1 = static_cast<Derived *>(pb);
    
        Derived *pd2 = dynamic_cast<Derived *>(pb);
    }

    在上面的代码段中,
    如果pb实际指向一个Derived类型的对象,pd1和pd2是一样的,并且对这两个指针执行Derived类型的任何操作都是安全的;
    如果pb实际指向的是一个Base类型的对象,那么pd1将是一个指向该对象的指针,对它进行Derived类型的操作将是不安全的(如访问m_szName),而pd2将是一个空指针(即0,因为dynamic_cast失败)。
    另外要注意:Base要有虚函数,否则会编译出错;static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。

    另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。
    class Base
    {
    public:
        int m_iNum;
        virtual void f(){}
    };
    
    
    
    class Derived1 : public Base
    {
    
    };
    
    class Derived2 : public Base
    {
    
    };
    
    void foo()
    {
        derived1 *pd1 = new Drived1;
    
        pd1->m_iNum = 100;
    
        Derived2 *pd2 = static_cast<Derived2 *>(pd1); //compile error
    
        Derived2 *pd2 = dynamic_cast<Derived2 *>(pd1); //pd2 is NULL
    
        delete pd1;
    }

    在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。
     

    reinpreter_cast

     

    用法:reinpreter_cast<type-id> (expression)

     

    说明:type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。



    该运算符的用法比较多。
     

    const_cast

     

    用法:const_cast<type_id> (expression)

     

    说明:该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。



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

    Voiatile和const类试。举如下一例:

    class B{
    
    public:
    int m_iNum;
    }
    
    void foo(){
    const B b1;
    b1.m_iNum = 100; //comile error
    B b2 = const_cast<B>(b1);
    b2. m_iNum = 200; //fine
    }


    上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。

    展开全文
  • 用于数值类型之间的转换,也可以用于指针之间的转换,编译时已经确定好,效率高,但须要自己保证其安全性。 (1)用于数值之间的转化, 可以在相关指针在void* 之间转换   (2)在基类和派生类之间进行转换(必须是...

    static_cast<type-id >( expression )  

    用于数值类型之间的转换,也可以用于指针之间的转换,编译时已经确定好,效率高,但须要自己保证其安全性。

    (1)用于数值之间的转化, 可以在相关指针在void* 之间转换

       


    (2)在基类和派生类之间进行转换(必须是有继承关系的两个类之间)

    上行转换:子类指针或引用转换成基类表示——安全

    下行转换:基类指针或引用转换成子类表示——危险(没有动态类型检查


       


    dynamic_cast < type-id> ( expression)

    只用于对象的指针和引用之间的转换,需要虚函数尤其是向下类型转换,是安全的。与static_cast不同,在下行转换,dynamic_cast会检查转换是否会返回一个被请求的有效的完整对象,否则返回值为NULL. 

    检测在运行时进行,是基于RTTI数据信息的,运行时检测,安全,但是效率低。

      

    dynamic_cast 如何保证转换是安全的?

    引入RTTI,其存储着类运行的相关信息,记录的类的名字和类的继承关系链。使得对象可以知道自己的名字以及在继承链中的位置。因为RTTI依赖于虚表,所以用dynamic_cast对应的类一定要有虚函数。


    const_cast< type-id> ( expression)

    这个转换类型操纵传递对象的const属性,或者是设置或者是移除:
    代码:
    class C {};
    const C *a = new C;
    C *b = const_cast<C *>(a);


    reinterpret_cast< type-id> ( expression)

    用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小。



    隐式类型转换

    1)两种常用的实现隐式类类型转换的方式:

    a、使用单参数的构造函数或N个参数中有N-1个是默认参数的构造函数

    b、使用operator目标类型() const

     

    例如:
    class Rational {

    public:
      ...
      operator double()const;                  // 转换Rational类成double类型
    };

    在下面这种情况下,这个函数会被自动调用:
    Rational r(1,2);                           // r
    的值是1/2 
    double d = 0.5 *r;                         //
    转换 r double,然后做乘法

     

    (2) 避免隐式类型转换:单参数的构造函数或N个参数中有N-1个是默认参数的构造函数声明之前加上explicit






    展开全文
  • C++类型隐式转换和显式转换

    千次阅读 2017-06-27 19:46:48
    隐式转换:编译器根据需要自动转换变量类型。 1、一些基本类型的转换 double d = 82.0; int i = d; 2、类的隐式转换,以下几种情况,类B能隐式转换成类A: (1)B公有继承A,然后用子类去初始化基类 class A{}; ...
  • C++ 隐式转换和显示转换(转)

    千次阅读 2020-07-31 13:45:03
    1)C++类型转换分为两种,一种为隐式转换,另一种为显式转换。 2)C++中应该尽量不要使用转换,尽量使用显式转换来代替隐式转换。 1隐式转换 定义:隐式转换是系统跟据程序的需要而自动转换的。 1)C++类型(char...
  • c++避免隐式转换

    千次阅读 2018-02-09 07:35:48
    C++有一个很方便的功能—隐式转换,比如有一个函数 void func(double f); 调用它的时候 func(5); func(5.0); 都是有效的。 但有时候,这个功能就很麻烦了。比如: class A{ public: A(const string&...
  • C++中的explicit关键字介绍

    万次阅读 2016-04-16 16:32:17
    C++中的explicit关键字介绍
  • 隐式类型转换

    千次阅读 2019-03-07 20:55:57
    C++ 的基本类型中并非是完全的对立,部分数据类型之间是可以进行隐式转换的。隐式转换指的是不需要用户干预,编译器私下进行的类型转换行为。很多时候用户可能都不知道发生了哪些转换。 为何要进行隐式转换C++ ...
  • C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。 C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多...
  • C++函数模板的显示调用与隐式调用

    千次阅读 2016-04-22 14:31:51
    C++函数模板可以显示调用与可以隐式调用首先定义函数模板:template inline const T& c_max (const T& a, const T& b) { return a ; }那么隐式调用也就是隐式的参数类型推导,根据参数类型决定函数模板的编译,如...
  • 隐式转换就是不带转换类型的转换 隐式转换:说白了就是在转换时不给系统提示具体的显示模型,让其自动转换,但是要记住一条编译器一般只支持自下而上的类型转换,例如int 转 float int a =4; float b= 5.56; b ...
  • C++:类的自动转换和强制类型转换

    千次阅读 2016-09-06 13:05:05
    C++:类的自动转换和强制类型转换标签(空格分隔): c++ 作者:陈小默C类的自动转换和强制类型转换 C如何处理内置类型转换 构造函数的自动转换 自动转换的条件 自动类型转换的流程 使用explicit关键字关闭隐式类型...
  • C++中explicit的用法

    万次阅读 多人点赞 2017-03-04 15:48:07
    C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用。 C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参...
  • 从void*类型隐式转换为int*类型

    千次阅读 2014-08-14 13:40:59
    最常见的差异之一是,C允许从void*隐式转换到其它的指针类型,但C++不允许。下列是有效的C代码:  5从void*类型隐式转换为int*类型  int*i=malloc(sizeof(int)*5);  但要使其在C和C++两者皆能运作...
  • C++ 中operator用法:隐式类型转换

    千次阅读 2013-06-26 09:20:10
    C++中的operator主要有两个作用,一是操作符的重载,一是操作符的转换。对于操作符的重载,许多人都不陌生,用以下这个小例子温故一下: class A {  public:  A operator +(A& oa){A a;a.num=oa.num+num;return...
  • class Test1 { public: Test1(int n) { num=n; }//普通构造函数 private: int num; }; class Test2 { public: explicit Test2(int n) { num=n; }//explicit(显式)构造函数 private:...
  • [深入理解C++(一)]类型转换(Type Casting)

    万次阅读 热门讨论 2012-10-31 22:28:14
    [深入理解C++(一)]类型转换(Type Casting) 罗朝辉 (http://blog.csdn.net/kesalin) CC许可,转载请注明出处 类型转换就是将给定类型的表达式转换为另一种类型C++中的转型可分为两种:隐式...
  • C++中的explicit关键字

    万次阅读 多人点赞 2008-12-09 22:42:00
    C++程序中很少有人去使用explicit关键字,不可否认,在平时的实践中确实很少能用的上。再说C++的功能强大,往往一个问题可以利用好几种C++特性去解决。但稍微留心一下就会发现现有的MFC库或者C++标准库中的相关类...
  • C++ 隐式和显式 初始化,类型转换

    千次阅读 2009-08-11 09:35:00
    1. 隐式和显式初始化1.1 C++隐式初始化int ival(1024);string hello("Hello world.")1.2 C++显式初始化int ival = 1024;string hello = "Hello world." *PS: 注意这里"=" 语法是拷贝构造函数而不是赋值运算! 因为...
1 2 3 4 5 ... 20
收藏数 53,691
精华内容 21,476
关键字:

c++隐式类型转换