[C++] 类型转换符static_cast、const_cast、dynamic_cast、reint
C++中为了避免松散的、无意义的类型转换,添加了四个类型转换操作符,以更严格地限制类型转换:static_cast,const_cast,reinterpret_cast,dynamic_cast,下面逐一看看他们的使用。 static_cast用隐式转换、或者用户定义转换的组合在类型间的转换,可以使用static_cast,该运算符语法格式如下: static_cast 仅当type_name可以被隐式转换为expression所属的类型时或者expression可以被隐式转换为type_name所属的类型时,可以使用static_cast. 它在以下场景时的类型转换时可用: 1.内置数据类型; 2.具有继承关系的类的指针和引用; 3.用户定义的可转换的类; 在继承类的指针或引用之间进行转换时,会把一个基类的指针转化成了一个派生类的指针,但实际上这个指针指向的还是原来的基类对象,因此在对virtual函数调用时需要注意其多态的特性。 如下示例中是对static_cast的使用: #include 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 double d2 = static_cast 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(&per); Person* pper = static_cast 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(per); Person& rper = static_cast 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 p.getName(); //不相关类不能使用 //Flower* pflo = static_cast 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_castconst_cast运算符则用于在有不同cv限定符之间的转换,也就是说在const和volatile之间进行转换,且只能用于指针、引用或指向成员类型的指针,如果使用对象,编译器将提示错误: 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 using namespace std; int main() { const int i = 20; int* k = const_cast cout << "before modify,k:" << *k << ",i:" << i << endl; *k = 40; cout << "after modify,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_castdynamic_cast运算符只能用于具有继承关系的类型之间的向上转换,且只能是指针或者引用。其语法格式如下: dynamic_cast 若转型成功,则返回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 #include 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(per); Animal ani; Person per; // 1.指针转换 Animal* pani = dynamic_cast(&per); Person* pper = dynamic_cast cout << "====指针转换=====" << endl; pani->show(); if (pper != NULL) pper->show(); else cout << "pper is null pointer" << endl; // 2.引用转换 cout << "====引用转换=====" << endl; Animal& rani = dynamic_cast(per); rani.show(); try{ Person& rper = dynamic_cast } catch (bad_cast& ex) { cerr << ex.what() << endl; } // 3.不相关的类不能使用 //Dog dog; //Person& rper2 = dynamic_cast return 0; } /* @ubuntu:~$ g++ dynamiccast.cpp -o dynamiccast @ubuntu:~$ ./dynamiccast ====指针转换===== Person show.... pper is null pointer ====引用转换===== Person show.... std::bad_cast */ dynamic_cast和static_cast都可以对具有继承关系的指针和引用进行向上转换,优先使用前者。 reinterpret_castreinterpret_cast可以用于处理任意无关类型的指针或引用的转换,以及指针类型转换为足以存储指针表示的整型。但他有如下限制: 1.不能删除const; 2.不能将指针转换为更小的整型或者浮点型; 3.不能将数据指针转换为函数指针. 使用示例如下: #include #include 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 Flower* flower = reinterpret_cast flower->show(); // 可以用于指针转换为足以存储指针表示的整型 int i = 20; int* pi = &i; long l = reinterpret_cast cout << "l value:" << l << endl; // 不能将指针转换为更小的整型或者浮点型 //short s = reinterpret_cast // 不能将数据指针转换为函数指针 PFunc p; //p = reinterpret_cast // 可以将函数指针转换为数据指针 Dog* pi2 = reinterpret_cast return 0; } int sum(int i) { return 2 * i; } 总的来说,使用reinterpret_cast是比较危险的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |