七、类型转换

(1)C语言中的转换

  • 隐式转换:由范围小的类型转换成范围大的类型
  • 格式:TypeName b = (TypeName)a;
    int n=10;
    float f=n;
    cout << f <

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

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

(3)static_cast

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

通常使用隐式转换

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

(4)const_cast

<1>说明
  • 去掉const修饰的不可修改特性,只是在const_cast中去掉该特性,其他时候还是const变量
<2>基础类型变量
  • 在<>里面不能用基本类型,只能用指针和引用
  • 基础类型const常量在使用时展开操作,类似在宏定义中展开(编译时之间进行值的替换),所以值没有变.
    const int a=10;
    //const_cast(a)=11;//注意:在<>里面不能用基本类型,只能用指针和引用
    const_cast(a)=12;//已经改变a所在内存的值
基础类型const常量在使用时展开操作,类似在宏定义中展开,所以a的值没有变
    cout << &a << "," << a <(pa)=11;
    cout << &a << "," << a <
<3>string类型的变量
    const string s("abcd");
    //s+="def";//报错
    cout << s <(s) +="def";
    cout << s <
<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(s1).Set(110);//const对象只能访问const成员函数,去掉s1的const属性,<>里要用引用
    cout << s1.Get() << endl;//110
    const Simple* ps1=&s1;
    cout << ps1->Get() << endl;//110
    const_cast(ps1)->Set(120);
    cout << ps1->Get() <
<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(getter);//法一
        //++(const_cast(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;iGetName()<Feature();
// 下行转换,把父类指针转换成子类指针。1.父类指针必须指向当前类型的子类对象。2.必须有虚函数。
        Cat* cat=dynamic_cast(arr[i]);//cat有两中结果:成功的话就是Cat*
        if(NULL!=cat){//失败的的话就是NULL
            cout << "抓了"<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(pD1);
    pD2->Print();//Derive2
}

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

(6)reinterpret_cast

  • 改变指针或引用的类型、
  • 对象指针的转化(A类对象指针转化成B类的对象指针,使用B类的成员函数)
<1>将整型转换为指针或引用类型。
    int n=100;
    //void* p=static_cast(n);
    void* p=reinterpret_cast(n);
    cout << p << endl;
<2>将指针或引用转换为一个足够长度的整型
    // 精度缺失不能转换
    // n = reinterpret_cast(p);
    // n = (int)p;
    long addr = reinterpret_cast(p);
    cout << addr << endl;
<3>函数指针与指针的转换
void Func(){
    cout << __func__ <(Func);
    void* pf=reinterpret_cast(Func);
    typedef void (*pfunc)();
    void (*func)()=reinterpret_cast(pf);
    void (*func)()=reinterpret_cast(pf);//和上面一样
<4>打印地址
  • 打印基本类型变量和数组的地址
    int n=10;
    int* p=&n;
    cout << p <
  • 打印字符串数组地址
    需要用static_cast
    const char* s="hello";
    cout << s <<" "<(s)<
  • 打印函数地址
    需要用reinterprete_cast
    void Func(){cout << __cplusplus <(&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 << "(" <(&point)<(&point.x)<(&Point3D::Print)<(&point.Print)<

(7)总结

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

你可能感兴趣的:(七、类型转换)