zoukankan      html  css  js  c++  java
  • C++Primer学习——类型转换

    无符号之间的运算

    当一个是无符号类型,另外一个是带符号类型:
    如果无符号不小于带符号,那么带符号转换成无符号。
    如果无符号小于带符号,当无符号类型的所有值都能存到带符号中时,则无符号转换成带符号,否则,
    带符号类型转换成无符号类型。
    比如:
    有两个类型分别是 long 和 unsigned int,如果大小相同,long类型转换成unsigned int,否则unsigned转换成long类型

    隐式类型:

    数组转换成指针:
    decltype,取地址&,sizeof以及typeid(未知)不会转换
    如果用一个引用初始化数组也不会发生转换。(引用初始化数组?)

    类类型定义的转换:

    string s;
    while(cin >> s)        //IO库定义了从istream向bool的转换规则,取决于是否读入成功
    {
    }
    

    显式转换:

    cast-name(exp); 将exp转换成type类型

    1、static_cast:(只要不包含底层const)

    主要在以下几种场合中使用:
    1.用于类层次结构中,基类和子类之间指针和引用的转换;
    当进行上行转换,也就是把子类的指针或引用转换成父类表示,这种转换是安全的;
    当进行下行转换,也就是把父类的指针或引用转换成子类表示,这种转换是不安全的,也需要程序员来保证;
    2.用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等等,这种转换的安全性需要程序员来保证;
    3.把void指针转换成目标类型的指针,是及其不安全的;
    注:static_cast不能转换掉expression的const、volatile和__unaligned属性。
    参考链接

    int a = 100;
    double t = static_cast<double>(a) / 6;
    cout << t << endl;  
    //16.6667
    

    向上转换(好像并不是肯定安全的记住原始的指针类型 ?):

    class Base1{
        //int a;
    };
    class Base2{
        public:
        int b;
    };
    class Derived: public Base1, public Base2{
    };
    int main()
    {
        int a;
        void *p;
        Derived pd;
        pd.b = 10;
        cout << pd.b <<endl;
        cout << "pb: " << &pd<< endl;
        Base2* pb1 = static_cast<Base2 *>(&pd);
        cout << pb1->b <<endl;
        cout << "Derived to Base2: " << pb1 << endl;
        return 0;
    }
    10
    pb: 0x68fefc
    10
    Derived to Base2: 0x68fefc
    

    2、const_cast:(只能改变底层const)

    使用const_cast去除const限定的目的不是为了修改它的内容,通常是为了函数能够接受这个实际参数

    const char *cp;
    char *p = const_cast<char*>(cp);//通过p写值是未定义行为
    char *p = static_cast<char*>(cp);//error
    static_cast<string>(cp);         //yes,字符串字面值转变成string(未实践)
    const int a = 100;
    int *pA = const_cast<int *>(&a);
    *pA = 200;
    int &refA = const_cast<int &>(a);
    refA = 300;
    //  int *pA1 = static_cast<int *>(&a);  Error   
    cout << "*pA:" << *pA << endl;//300  
    cout << "refA:" << refA << endl;//300  
    cout << "a:" << a << endl;//100  
    system("pause");
    

    下面是网上摘录的一段解释:(or常量折叠解释)
    const只是告诉编译器不能修改而不是真正地不可修改,如果程序员不注意而去修改了它会报错,现在我们利用const_cast去除了常量性,然后通过指针和引用对其进行了修改,所以通过指针打印或者引用传参的时候就能看出其内存确实变化了,但为了保护val这个变量本来的const特性,所以每次我们使用val时,系统都将其替换成初始值100,确保了val还是“不可变”的
    参考博客

    #include <iostream>
    using namespace std;
    void f(int* p) {
      cout << *p << endl;
    }
    int main(void) {
      const int a = 10;
      const int* b = &a;
      // Function f() expects int*, not const int*
      //   f(b);
      int* c = const_cast<int*>(b);
      f(c);
      // Lvalue is const
      //  *b = 20;
      // Undefined behavior
      //  *c = 30;
      int a1 = 40;
      const int* b1 = &a1;
      int* c1 = const_cast<int*>(b1);
      // Integer a1, the object referred to by c1, has
      // not been declared const
      *c1 = 50;
      return 0;
    }
    http://www.ibm.com/support/knowledgecenter/SS3KZ4_9.0.0/com.ibm.xlcpp9.bg.doc/language_ref/keyword_const_cast.htm
    

    在函数重载上面的应用:

    const string &shorterString(const string& a, const string& b)
    {
    return a.size() <= b.size() ? a : b;
    }
    string &shorterString(string& a, string& b)
    {
    auto &r = shorterString(const_cast<const string&>(a),
    const_cast<const string&>(b));
    return const_cast<string &>(r);
    }
    

    3、reinterpret_cast:(本质上依赖于机器)

    可以进行任意之间的转换,不会报错,但是可能破坏程序

    int *ip;
    char *pc = reinterpret<char*>(ip);
    string str(pc);                            //pc所指真实对象是一个int,所以有问题
    与旧式转换类似的功能
    int *op;   
    char *p = (char*)op;
    MSDN上的一个应用- -  ,不是很懂reinteroret_cast有什么用
    #include <iostream>  
    using namespace std;  
      
    // Returns a hash code based on an address  
    unsigned short Hash( void *p ) {  
       unsigned int val = reinterpret_cast<unsigned int>( p );  
       return ( unsigned short )( val ^ (val >> 16));  
    }  
      
    using namespace std;  
    int main() {  
       int a[20];  
       for ( int i = 0; i < 20; i++ )  
          cout << Hash( a + i ) << endl;  
    }
    

    4.dynamic_cast转换 :

    (想使用基类指针或者引用执行某个派生类非虚函数操作)
    dynamic_cast是动态转换,只有在基类指针转换为子类指针时才有意义。(子类指针转换为基类指针本来就是可以的:基类指针指向子类对象OK)。
    但是基类指针转换为子类指针,并不是每一次都有效:只有基类指针本身指向的是一个派生类的对象,
    安全性:
    这需要从它的返回值进行讨论,如果符合继承体系且原始指针是指向派生类的对象的,那么返回值将是一个正确的指针值,否则会返回NULL。所以,我们可以对返回值进行判断来进行断定到底转换是否正确,从而保证程序的健壮性
    必须是一个带有虚函数的类。因为dynamic_cast是在对象的内存模型中保存了offset值来实现转换的,这些offset值是保存在虚表(vtbl)中的
    虚表参考<Inside c++ object model>:

    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
        }
    }
    
    class A
    {
    public:
       virtual ~A(){}         //虚函数 多态
    };
    class B:public A
    {
    public:
        int m;
    };
    A* pObjA = new A();
    B* pObjB  = NULL;
    pObjB = dynamic_cast<B*>(pObjA);  //编译通过 
    //实际运行结果:pObjB == NULL   // dynamic_cast保证转换无效 返回NULL
    

    来自为知笔记(Wiz)

  • 相关阅读:
    Oracle数据库编程
    使用JDBC处理MySQL大文本和大数据
    phpcms之带图片的登录信息(带cookie版)(由于cookie和PHPCMS的原因,这个暂时无法使用,看新的)
    phpcms之调用导航栏
    phpcms之修改默认显示文字
    phpcms之创建自己的路径
    dedecms 动态tab写法
    关于dedecms的操作
    12/23
    12/21
  • 原文地址:https://www.cnblogs.com/Przz/p/6413872.html
Copyright © 2011-2022 走看看