[C++] 类型转换符static_cast、const_cast、dynamic_cast、reinterpret_cast

C++中为了避免松散的、无意义的类型转换,添加了四个类型转换操作符,以更严格地限制类型转换:static_castconst_castreinterpret_castdynamic_cast,下面逐一看看他们的使用。

static_cast

用隐式转换、或者用户定义转换的组合在类型间的转换,可以使用static_cast,该运算符语法格式如下:

static_cast<type-name>(expression);

仅当type_name可以被隐式转换为expression所属的类型时或者expression可以被隐式转换为type_name所属的类型时,可以使用static_cast.
它在以下场景时的类型转换时可用:

  • 1.内置数据类型;
  • 2.具有继承关系的类的指针和引用;
  • 3.用户定义的可转换的类;

在继承类的指针或引用之间进行转换时,会把一个基类的指针转化成了一个派生类的指针,但实际上这个指针指向的还是原来的基类对象,因此在对virtual函数调用时需要注意其多态的特性。

如下示例中是对static_cast的使用:

#include <iostream>
using namespace std;

class Animal{
public:
        virtual void show() {
                cout << "Animal show...." << endl;
        }
};
class Person : public Animal{
private:
        std::string name;
public:
        Person(){}
        //转换构造函数
        explicit Person(std::string& name):name(name){}
        virtual void show() {
                cout << "Person show...." << endl;
        }
        virtual void getName() { cout << "Person's name:" << name << endl;}
};

class Flower{};

int main()
{
        //1.隐式转换内置类型

        cout << "====内置数据类型转换====" << endl;
        double d1 = 3.14;
        int i1 = 4;
        int i2 = static_cast<int>(d1);
        double d2 = static_cast<double>(i1);
        cout << "i:"<< i2 << ",d:" << d2 << endl;
            
        Animal ani;
        Person per;

        cout << "====对象地址====" << endl;
        cout << "ani address:" << &ani << ",per address: " << &per << endl;

        //2.具有继承关系的类的指针
        cout << "====指针转换====" << endl;
        Animal* pani = static_cast<Animal*>(&per);
        Person* pper = static_cast<Person*>(&ani);

        cout << "Animal* pani->show():   ";
        pani->show();
        cout << "Person* pper->show():   ";
        pper->show();
        cout << "pani:" << pani << ", pper: " << pper << endl;
        //pper类型为Person*,但实际指向Animal对象,因此,调用将出现Segmentation fault
        //若取掉该方法的virtual关键字,则不该方法多态特性消失,可以调用
        //pper->getName();
            
        //3.具有继承关系的类的引用
        Animal& rani = static_cast<Animal&>(per);
        Person& rper = static_cast<Person&>(ani);
        cout << "====引用转换====" << endl;
        cout << "rani address: " << &rani << ", rper address: " << &rper << endl;
        rani.show();
        rper.show();
        //rper类型为Person&,但引用的是Animal对象,因此调用将出现Segmentation fault,
        //若取掉该方法的virtual,则不该方法多态特性消失,可以调用
        //rper.getName();

        //4.用户组合的可以进行隐式转换类之间的转换
        cout << "====string转换为Person:====" << endl;
        string str("person1");
        Person p = static_cast<Person>(str);
        p.getName();

        //不相关类不能使用      
        //Flower* pflo = static_cast<Flower*>(&ani);
        return 0;
}
/*
编译并运行:
@ubuntu:~$ g++ staticcast.cpp -o staticcast
@ubuntu:~$ ./staticcast 
====内置数据类型转换====
i:3,d:4
====对象地址====
ani address:0x7ffe798cd2b0,per address: 0x7ffe798cd310
====指针转换====
Animal* pani->show():   Person show....
Person* pper->show():   Animal show....
pani:0x7ffe798cd310, pper: 0x7ffe798cd2b0
====引用转换====
rani address: 0x7ffe798cd310, rper address: 0x7ffe798cd2b0
Person show....
Animal show....
====string转换为Person:====
Person's name:person1
*/

const_cast

const_cast运算符则用于在有不同cv限定符之间的转换,也就是说在constvolatile之间进行转换,且只能用于指针、引用或指向成员类型的指针,如果使用对象,编译器将提示错误:

error: invalid use of const_cast with type ‘int’, which is not a pointer, reference, nor a pointer-to-data-member type

使用const_cast示例如下:

#include <iostream>

using namespace std;

int main()
{

        const int i = 20; 
        int* k = const_cast<int*>(&i);
    
        cout << "before modify,k:" << *k << ",i:" << i << endl;
        *k = 40;
        cout << "after modify,k:" << *k << ",i:" << i << endl;
        return 0;
}
/*
编译并运行:
@ubuntu:~$ g++ constcast.cpp -o constcast
@ubuntu:~$ ./constcast 
before modify,k:20,i:20
after modify,k:40,i:20
*/

通过以上示例还可以发现,虽然将i的const取消了,但是依然无法修改i的值,所以说const_cast虽然可以取消指针的const性,但无法修改const值。

dynamic_cast

dynamic_cast运算符只能用于具有继承关系的类型之间的向上转换,且只能是指针或者引用。其语法格式如下:

dynamic_cast <type-name>(expression) 		

若转型成功,则返回type-name的值,若转型失败且type-name是指针类型,则返回该类型的空指针,若转型失败且type-name是引用类型,则它将抛出bad_cast异常。

此外,dynamic_cast会进行运行时类型识别,而所需信息是存储在虚函数表中的,因此需要有virtual方法,以生成虚函数表,否则将出现如下异常:

error: cannot dynamic_cast& ani’ (of type ‘class Animal*) to type ‘class Person*(source type is not polymorphic)

使用示例如下:

#include <iostream>
#include <typeinfo>

using namespace std;

class Animal{
public:
        virtual void show() {
                cout << "Animal show...." << endl;
        }
};
class Person : public Animal{
private:
        string name;
public:
        Person(){ this->name = "None";}
        Person(string & name):name(name){}
        virtual void show() {
                cout << "Person show...." << endl;
        }
        virtual void getName() { cout << "Person's name:" << name << endl;}
};

class Dog : public Animal
{
public:
        virtual void show() {
                cout << "Dog show...." << endl;
        }
};

int main()
{
        //不能使用对象转换,只能是指针或引用
        //Animal a = dynamic_cast<Animal>(per);
    
        Animal ani;
        Person per;
    
        // 1.指针转换
        Animal* pani = dynamic_cast<Animal*>(&per);
        Person* pper = dynamic_cast<Person*>(&ani);
        cout << "====指针转换=====" << endl;
        pani->show();
        if (pper != NULL)
                pper->show();
        else 
                cout << "pper is null pointer" << endl;

        // 2.引用转换
        cout << "====引用转换=====" << endl;
        Animal& rani = dynamic_cast<Animal&>(per);
        rani.show();
        try{
                Person& rper = dynamic_cast<Person&>(ani);
        } catch (bad_cast& ex) {
                cerr << ex.what() << endl;
        }
    
        // 3.不相关的类不能使用
        //Dog dog;
        //Person& rper2 = dynamic_cast<Person&>(dog);
        return 0;
}

/*
@ubuntu:~$ g++ dynamiccast.cpp -o dynamiccast
@ubuntu:~$ ./dynamiccast 
====指针转换=====
Person show....
pper is null pointer
====引用转换=====
Person show....
std::bad_cast
*/

dynamic_caststatic_cast都可以对具有继承关系的指针和引用进行向上转换,优先使用前者。

reinterpret_cast

reinterpret_cast可以用于处理任意无关类型的指针或引用的转换,以及指针类型转换为足以存储指针表示的整型。但他有如下限制:

  • 1.不能删除const;
  • 2.不能将指针转换为更小的整型或者浮点型;
  • 3.不能将数据指针转换为函数指针.

使用示例如下:

#include <iostream>
#include <typeinfo>

using namespace std;

class Dog{};

class Flower {
public:
        void show() {
                cout << "Flower show..." << endl;
        }   
};


typedef int (*PFunc)(int);

int sum(int i); 

int main()
{
        Flower oflo;
        // 可以用于任意类型的指针/引用的转换    
        Dog* od = reinterpret_cast<Dog*>(&oflo);
        Flower* flower = reinterpret_cast<Flower*>(od);
        flower->show();

        // 可以用于指针转换为足以存储指针表示的整型
        int i = 20; 
        int* pi = &i; 
        long l = reinterpret_cast<long>(pi);
        cout << "l value:" << l << endl;

        // 不能将指针转换为更小的整型或者浮点型
        //short s = reinterpret_cast<short>(pi);

        // 不能将数据指针转换为函数指针
        PFunc p;
        //p = reinterpret_cast<PFunc*>(&i);
        // 可以将函数指针转换为数据指针
        Dog* pi2 = reinterpret_cast<Dog*>(sum); 
        return 0;
}

int sum(int i) {
        return 2 * i;
}

总的来说,使用reinterpret_cast是比较危险的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值