美文网首页程序员
七、类型转换

七、类型转换

作者: __bba3 | 来源:发表于2020-05-16 10:35 被阅读0次

(1)C语言中的转换

  • 隐式转换:由范围小的类型转换成范围大的类型
  • 格式:TypeName b = (TypeName)a;
    int n=10;
    float f=n;
    cout << f <<endl;//10
    float ff=10.2;
    n=ff;//截取
    cout << n <<endl;//10
    int* p=&n;
    void* v=p;//隐式转换
    p=(int*)v;//显示转换

(2)C++11提供了四种转换方式

  • 语法:xxx_cast<要转换的类型>(被转换的变量)
  • 作用:(1)细化准换类型;(2)提供安全性的检测;(3)在代码中更加醒目

(3)static_cast

<1>说明
  • 用于非多态类型之间的转换,不提供运行时的检查来确保转换的安全性。
  • c++ 的任何的隐式转换都是使用 static_cast 来实现。
<2>基本类型的转换
    char c='a';
    cout << c <<endl;//a
    cout <<(int)c <<endl;//97(C语言方式)
    cout << static_cast<int>(c)<<endl;//97(C++中的转换)
<3>指针的转换
    int* arr1=(int*)malloc(sizeof(int)*10);
    int* arr2=static_cast<int*>(malloc(10*sizeof(int)));
<4>枚举
enum BOOL{FALSE,TRUE};
    //BOOL b=0;//不能从int转换为BOOL
    //BOOL b=(1==2);//不能从bool转换为BOOL
    BOOL bb=static_cast<BOOL>(0);
    BOOL b=static_cast<BOOL>(1==2);
<5>基类和子类之间指针和引用的转换
  • 上行转换
    上行转换,把子类的指针或引用转换成父类,这种转换是安全的(通常使用默认转换)。
class Base{};
class Sub: public Base{};
//  上行 Sub -> Base
//编译通过,安全
Sub sub;
Base *base_ptr = static_cast<Base*>(new Sub); 

通常使用隐式转换

Base* pb=new Sub;
  • 下行转换
    下行转换,把父类的指针或引用转换成子类,这种转换是不安全的,也需要程序员来保证(通常使用dynamic_cast)。
//  下行 Base -> Sub
//编译通过,不安全,需要使用dynamic_cast
Base base;
Sub *sub_ptr = static_cast<Sub*>(&base);  

(4)const_cast

<1>说明
  • 去掉const修饰的不可修改特性,只是在const_cast中去掉该特性,其他时候还是const变量
<2>基础类型变量
  • 在<>里面不能用基本类型,只能用指针和引用
  • 基础类型const常量在使用时展开操作,类似在宏定义中展开(编译时之间进行值的替换),所以值没有变.
    const int a=10;
    //const_cast<int>(a)=11;//注意:在<>里面不能用基本类型,只能用指针和引用
    const_cast<int&>(a)=12;//已经改变a所在内存的值
基础类型const常量在使用时展开操作,类似在宏定义中展开,所以a的值没有变
    cout << &a << "," << a <<endl;//0xabcd,10 // 常量展开,看不到改变
    const int* pa=&a;
    cout << pa << "," << *pa <<endl;//0xabcd,12 
    *const_cast<int*>(pa)=11;
    cout << &a << "," << a <<endl;//0xabcd,10 
    cout << pa << "," << *pa <<endl;//0xabcd,11
<3>string类型的变量
    const string s("abcd");
    //s+="def";//报错
    cout << s <<endl;//abcd
    const_cast<string&>(s) +="def";
    cout << s <<endl;//abcddef
<4>类类型的对象
class Simple{
    int n;
public:
    Simple(int n):n(n){}
    void Set(int n){this->n=n;}
    int Get()const{return n;}
};
    const Simple s1(100);
    cout << s1.Get() << endl;//100
    const_cast<Simple&>(s1).Set(110);//const对象只能访问const成员函数,去掉s1的const属性,<>里要用引用
    cout << s1.Get() << endl;//110
    const Simple* ps1=&s1;
    cout << ps1->Get() << endl;//110
    const_cast<Simple*>(ps1)->Set(120);
    cout << ps1->Get() <<endl;//120
<5>const成员函数中修改成员变量
  • const函数中所有成员变量都有const属性。
  • const成员函数的本质:const函数中this指针是const类型,所以说所有成员不能修改。
  • const成员函数中修改成员变量有3中方法:
    (1)把需要修改的成员变量const_cast<>()转成非const类型
    (2)把this使用const_cast<>()转换成非const类型,然后修改成员变量
    (3)mutable的成员变量可以在const函数中修改
提供一个打印出Set/Get次数的函数
class Integer{
    int n;
    int setter;
    mutable int getter;//法三
public:
    Integer(int n):n(n),setter(0),getter(0){}
    void Set(int n){//非const成员函数中可以直接修改成员变量的值
        ++setter;
        this->n=n;
    }
    int Get()const{//const成员函数不能直接修改成员变量的值
        //++const_cast<int&>(getter);//法一
        //++(const_cast<Integer*>(this)->getter);//法二
        ++getter;
        return n;
    }

(5)dynamic_cast

用于类的指针、类的引用或者void *转化,dynamic_cast只在多态有效。

<1>说明

主要用于以下种情况:

  • 上行转换、下行转换、交叉转换
<2>上行转换
  • 上行转换:把子类的指针或引用转换成父类,与static_cast相同。
<3>下行转换
  • 下行转换:把父类的指针或引用转换成子类,dynamic_cast具有类型检查的功能,比static_cast安全。使用时的2个条件:
    (1)父类指针必须指向当前类型的子类对象;
    (2)至少有一个虚函数
class Animal{
    string name;
public:
    Animal(const string& name):name(name){}
    virtual string Feature()const=0;//虚函数或者纯虚函数都行
    //virtual string Feature()const{return " ";}
    const string& GetName()const{return name;}  
};
class Cat:public Animal{
    int n;
public:
    Cat(const string& name,int n):Animal(name),n(n){}//注意:对于非默认构造函数的编写
    string Feature()const{return "抓老鼠";}
    int GetMouseNum()const{return n;}
};

class Dog:public Animal{
public:
    Dog(const string& name):Animal(name){}
    string Feature()const{return "看门";}
};
void Display(Animal** arr,int n){//或者Animal** arr
    for(int i=0;i<n;++i){
        cout <<arr[i]->GetName()<<arr[i]->Feature();
// 下行转换,把父类指针转换成子类指针。1.父类指针必须指向当前类型的子类对象。2.必须有虚函数。
        Cat* cat=dynamic_cast<Cat*>(arr[i]);//cat有两中结果:成功的话就是Cat*
        if(NULL!=cat){//失败的的话就是NULL
            cout << "抓了"<<cat->GetMouseNum() << "只老鼠";
        }
        cout << endl;
    }
}
int main(){
    Animal* arr[]={new Cat("猫",5),new Dog("狗")};
    Display(arr,2);
}

如果时指针,进行正确的转换,获得对应的值;否则返回NULL,如果是引用,则在运行时就会抛出异常;

  • 向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
<4>交叉转换

交叉转换,兄弟之间指针转换

class Base {
public:
  void Print() { cout << "Base" << endl; }
  virtual ~Base(){}
};
class Derive1 : public Base {
public:
  void Print() { cout << "Derive1" << endl; }
};
class Derive2 : public Base {
public:
  void Print() { cout << "Derive2" << endl; }
};

int main() { 
    Derive1* pD1 = new Derive1;
    pD1->Print();//Derive1
    Derive2 *pD2 = dynamic_cast<Derive2*>(pD1);
    pD2->Print();//Derive2
}

dynamic_cast为什么只在多态的继承关系才有效?由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表。

(6)reinterpret_cast

  • 改变指针或引用的类型、
  • 对象指针的转化(A类对象指针转化成B类的对象指针,使用B类的成员函数)
<1>将整型转换为指针或引用类型。
    int n=100;
    //void* p=static_cast<void*>(n);
    void* p=reinterpret_cast<void*>(n);
    cout << p << endl;
<2>将指针或引用转换为一个足够长度的整型
    // 精度缺失不能转换
    // n = reinterpret_cast<int>(p);
    // n = (int)p;
    long addr = reinterpret_cast<long>(p);
    cout << addr << endl;
<3>函数指针与指针的转换
void Func(){
    cout << __func__ <<endl;
    cout << __cplusplus <<endl;//输出编译器版本
}
     //void* pf=static_cast<void*>(Func);
    void* pf=reinterpret_cast<void*>(Func);
    typedef void (*pfunc)();
    void (*func)()=reinterpret_cast<void(*)()>(pf);
    void (*func)()=reinterpret_cast<pfunc>(pf);//和上面一样
<4>打印地址
  • 打印基本类型变量和数组的地址
    int n=10;
    int* p=&n;
    cout << p <<endl;
    
    int arr[]={1,2,4};
    cout << arr <<endl;
  • 打印字符串数组地址
    需要用static_cast
    const char* s="hello";
    cout << s <<" "<<static_cast<const void*>(s)<<endl;//直接打印会打印出字符串的值
    printf("%s\n",s);
    printf("%p\n",s);
  • 打印函数地址
    需要用reinterprete_cast
    void Func(){cout << __cplusplus <<endl;}//c++编译器的版本
    //cout << Func <<endl;//直接打印函数名为1
    cout << (void*)Func <<endl;//C语言方式
    cout << reinterpret_cast<void*>(&Func) <<endl;
    printf("%p\n",Func);
<5>类中的偏移量和地址
  • 【&类名::成员变量】: 获取成员变量在对象中的偏移量
  • 【&对象.成员变量】: 获取成员变量的地址
class Point3D{
public:
    int x,y,z;
    Point3D(int x,int y,int z):x(x),y(y),z(z){}
    void Print()const{
        cout << "(" <<x << "," << y <<","<<z<<")"<<endl;
    }
};
int main(){
    Point3D point(1,2,3);
    point.Print();
1.成员变量在对象中的偏移量
printf("%d %d %d\n",&Point3D::x,&Point3D::y,&Point3D::z);//必须加&,因为不是static成员变量,没有这种访问方式
结果:0 4 8    
cout << &Point3D::x <<' '<<&Point3D::y <<' '<<&Point3D::z <<endl;
结果:1 1 1(没啥用)
所以:要想打印对象中成员变量的偏移量需要用printf
2.对象的地址
    printf("%p\n",&point);
    cout << reinterpret_cast<void*>(&point)<<endl;
输出:0061FF04
3.成员变量的地址
    printf("%p %p %p\n",&point.x,&point.y,&point.z);
    cout << reinterpret_cast<void*>(&point.x)<<endl;
输出:0061FF04 0061FF08 0061FF0C
所以:成员变量的地址等于对象地址加上成员变量的偏移量
4.成员函数的地址
    cout <<(void*)&Point3D::Print<<endl;
    cout << reinterpret_cast<void*>(&Point3D::Print)<<endl;//获取成员函数地址必须加&
    cout << reinterpret_cast<void*>(&point.Print)<<endl;

(7)总结

No. 转换 转换对象 作用 转换时机
1 static_cast 基本类型、指针、引用 实现传统的小括号转化功能 在编译期间实现转换
2 const_cast const 类型的对象、指针、引用 移除变量const限定 在编译期间实现转换
3 dynamic_cast 类的指针、类的引用或者void * 多态父类指针/引用转化成子类指针/引用 在运行期间实现转换,并可以返回转换成功与否的标志/抛出异常,有类型检查
4 reinterpret_cast 指针、引用、算术类型 万能强制类型转换 在编译期间实现转换

相关文章

  • 七、类型转换

    (1)C语言中的转换 隐式转换:由范围小的类型转换成范围大的类型 格式:TypeName b = (TypeNam...

  • lesson22

    一、类型转换 1. 七种类型的转换 2. 转成boolean的五个falsy值 注意:所有object转换成boo...

  • C语言类型转换

    类型转换的方式 自动类型转换1.运算转换(规则:会把小类型转换为大类型) 2.赋值转换 强制类型转换格式:(类型)...

  • 引用类型转换

    向上类型转换(自动类型转换),是小类型到大类型的转换向下类型转换(强制类型装换),是大类型到小类型的转换在强制类型...

  • 第三章 JavaScript中的数据间类型的转换

    数据的类型转换分为强制类型转换和非强制类型转换,强制类型转换也可以称为显示转换,非强制类型转换也可以称为隐式转换。...

  • 笔记2018-08-28

    类型转换 自动类型转换运算转换(编译器会自动把小类型转换为大类型) 赋值转换(将等号右边的类型转换为等号左边的类型...

  • 四、SQL函数④(其他函数)

    类型转换 隐式转换:数据库系统自动将字符串类型转换为整数类型显式转换:使用类型转换函数转换。使用类型转换函数不仅可...

  • 4_类型转换

    关键词:类型之间的转换、强制类型转换、隐式类型转换 1. 类型之间的转换 C语言中的数据类型可以进行转换,转换方式...

  • 学习记录

    类型转换as?类型转换,转换成功,返回一个可选类型,转换不成功返回nilas!类型转换,转换失败回报运行错误备注:...

  • 回顾Date.0402(类型转换、运算)

    类型转换 隐式转换 显式转换 转换为Boolean类型:Boolean(xxx) ; !!xxx 数字类型转换为布...

网友评论

    本文标题:七、类型转换

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