文章目录
1、term2:尽量使用C++类型的风格转换
类型转换是一般程序员所不能忍受的,但是在紧要关头,类型转换是必须的。C风格的类型转换太过简单,粗暴,不能进行精确的类型转换;为了弥补C转换上功能的不足,C++提供了四种常用的类型转换来应付复杂的转换需求。
1.1 static_cast
static_cast用于在编译时执行类型转换,主要用于相对安全的类型转换,比如基本数据类型的转换,具有继承关系的指针或引用之间的转换。
1.1.1 基本数据类型转换
用于基本数据类型之间的隐式转换,这种情况下使用static_cast更为明确。举个栗子:
#include <iostream>
int main(){
double myDouble = 3.14;
int myInt = static_cast<int>(myDouble);
std::cout <<"Double: "<<myDouble<< ", Int : "<<myInt <<std::endl;
return 0;
}
在这个例子中。通过static_cast将double类型的变量转化为int类型的变量,使用static_cast一目了然。
1.1.2 指针类型转换
static_cast也可以用于在指针类型之间进行安全转换,避免一些问题,例如在基类和派生类之间进行转换。
#include <iostream>
using namespace std;
class Base{
public:
virtual ~Base(){}
};
class Derived: public Base{
public:
void derivedFunction(){
cout << "Derived function."<<endl;
}
}
int main(){
Base* basePtr = new Derived;
Derived* derivedPtr = static_cast<Derived*>(basePtr);
derivedPtr->derivedFunction(); //安全地调用派生类函数
delete basePtr;
return 0;
}
程序运行输出:
Derived function.
在这个例子中,basePtr是一个指向基类的指针,通过static_cast将其转换为指向派生类对象的指针,从而可以安全地调用派生类函数。如果存在不安全的类型转换,可以考虑使用dynamic_cast进行运行时检查。
1.2 const_cast
const_cast用于类型转换掉表达式的const或者volatileness属性,他也仅仅只能改变一些东西的constness和volatileness属性,如果做这两个属性之外的转换,将会被编译器拒绝。
const_cast并没有真正去除复合类型中const和volatile属性。值得注意的是:变量本身的const属性是不能去除的,要想修改变量的值,一般是去除指针(或引用)的const属性,再进行间接修改。通过const_cast运算符,也只能将const type转换为type,将const type&转换为type&。也就是说源类型和目标类型除了const属性不同,其他地方完全相同。
1.2.1 去除const限定符
举个栗子:
class Widget{...};
class SpecialWidget:public Widget{...};
void update(SpecialWidget *psw);
SpecialWidget sw;
//sw是一个非const对象
const SpecialWidget& csw = sw ;
//csw是sw的一个引用,它是一个const对象
update(&csw);
//error,不能将一个const SpecialWidget*变量传递给一个处理SpecialWidget*类型变量的函数
update(const_cast<SpecialWidget*>(&csw));
//true csw的const被显性转换掉,
update((SpecialWidget*)(&csw));
//同上,但是使用了C风格的类型转换
1.3 dynamic_cast
dynamic_cast,这种转换被用于安全地沿着继承关系向下进行类型转换,能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或兄弟类的指针或引用,并且能够知道转换是否成功,转换失败后会返回空指针或者抛出异常。
下面介绍dynamic_cast的使用场景:
1.3.1 在继承层次中进行安全的向下类型转换
当基类指针或引用指向派生类对象时,通过“dynamic_cast”进行向下类型转换,以确保类型的正确性。
举个栗子:
#include <iostream>
using namespace std;
class Base{
public:
virtual ~Base(){}
};
class Derived: public Base{
public:
void derivedFunction(){
cout << "Derived function."<<endl;
}
}
int main(){
Base* basePtr = new Derived;
if(Derived* derivedPtr = dynamic_cast<Derived*>(basePtr){
// 安全地使用derivedPtr
derivedPtr->derivedFunction();
}else{
//处理失败的情况
cout << "error !" << endl;
}
return 0;
}
1.3.2 处理多态类型的情况
举个栗子:
#include<iostream>
using namespace std;
class Animal{
public:
virtual void makeSound() const{
cout << "Some generic sound." << endl;}
};
class Dog :public Animal{
public:
void makeSound()const override{
cout << "Woof Woof!"<<endl;
}
};
class Cat:public Animal{
public:
void makeSound()const override{
cout << "Meow Meow!"<<endl;
}
};
};
//Animal是基类,Dog,cat都是派生类,它们都重写了虚函数makesound
void animalSound(const Animal& animal){
//使用dynamic_cast进行向下类型转换
if(const Dog* dog = dynamic_cast<const Dog*>(&animal)){
cout << "Dog says: ";
dog->makeSound();
}else if(const Dog* dog = dynamic_cast<const Cat*>(&animal)){
cout << "Cat says: ";
cat->makeSound();
}else{
cout << "Unknown ainmal sound" <<endl;
}
}
int main(){
Dog myDog;
Cat myCat;
animalSound(myDog);
animalSound(myCat);
return 0;
}
输出内容:
Dog says: Woof Woof!
Cat says: Meow Meow!
...Program finished with exit code 0
Press ENTER to exit console.
在这个例子中,animalSound函数接受一个基类对象的引用,使用dynamic_cast将其向下类型转换为派生类对象,不同的类型调用不同的派生函数,这样可以在运行时动态确定对象的实际类型。
1.4 reinterpret_cast
reinterpret_cast是C++进行底层类型转换的一种强制类型转换。这种转换非常强大,也十分危险,因为他可以绕过类型系统,导致未定义的行为。下面介绍几个使用场景:
1.4.1指针类型之间的转换
#include<iostream>
using namespace std;
int main(){
int value = 42;
//将整数指针转换为字符指针
char* charPtr = reinterpret_cast<char*>(&value);
for(size_t i = 0;i < sizeof(int);i++){
cout << "Byte " << i << static_cast<int>(charPtr[i]) << endl;
}
return 0;
}
输出:
Byte 0 42
Byte 1 0
Byte 2 0
Byte 3 0
这个例子中,将一个整数指针转化为字符指针,然后通过字符指针输出整数在内存中的每一个字节;这样的转换通常用于底层的内存操作。
1.4.2整数和指针之间的转换
#include <iostream>
using namespace std;
int main(){
int value = 42;
//将整数转换为指针
void* voidPtr = reinterpret_cast<void*>(value);
//将指针再转为整数
int* intPtr = reinterpret_cast<int*>(voidPtr);
//输出转型后的整数数值
cout << "Original:" << value <<", Back to int :" <<*intPtr << endl;
return 0;
}
在上述例子中,将一个整数转化为void* 指针,然后再转为整数指针;这种转换通常用于低级别的内存操作。
关于reinterpret_cast,转换函数指针的代码是不可移植的,所以在日常使用中应该避免转换函数指针类型,除非你身处险境,需要背水一战;不到万不得已,都不要使用。
2、总结
书山有路勤为径,学海无涯苦作舟。
3、参考
3.1 《More Effective C++》