Cast Operation in C++
Introduction
在用C++写一些Lab和项目的时候,涉及到cast在C++里的应用。发现自己并不熟悉这些东西,于是也仅仅在阅读一些博客后草草了事,没有很深的记忆。但是过一段时间之后,又全部都忘记了,所以想写一个博客来记录一下加深自己的理解。
C++是一种强类型语言,当需要把一个变量按照使用需求转化为另一个变量的时候,就需要用到类型转换。C++提供了四种类型转换的方法:
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast
下面我们一个个的理解它们。
static_cast
Static_cast是在C++中最常用的casting方法。它可以用来在不同相关类型间做转换,例如数值类型(int,float)或者在父子类中转换。
int a = 3;
float b = static_cast<int>(a);
上面是简单的数值类型转换,替换了之前的隐式转换。
下面通过一个例子说明class类型。
假设有一个父类class animal,两个继承animal的子类dog和cat,代码如下:
class Animal {
public:
virtual void makeSound() { std::cout << "The animal makes a sound\n"; }
};
class Dog : public Animal {
public:
void makeSound() override { std::cout << "The dog barks\n"; }
void wagTail() { std::cout << "The dog wags its tail\n"; }
};
class Cat : public Animal {
public:
void makeSound() override { std::cout << "The cat meows\n"; }
void purr() { std::cout << "The cat purrs\n"; }
};
现在我们来看看如何使用static_class
。
Upcasting:Upcasting是将指向子类的指针转化为指向父类的指针,这样的操作在C++中是认为安全的。
Dog* dog = new Dog(); Animal* animal = static_cast<Animal*>(dog); // Upcasting animal->makeSound(); // Outputs: "The dog barks"
Downcasting:Downcasting相反,将指向父类的指针指向子类。这是一种不安全的操作,因为父类的object可能并不是子类的object,这时候调用子类的object就会出现Undefined behavior。
Animal* animal = new Animal(); Dog* dog = static_cast<Dog*>(animal); // Unsafe downcasting dog->makeSound(); // Undefined behavior!
安全的downcasting是这样的:
Animal* animal = new Dog(); // The Animal is actually a Dog Dog* dog = static_cast<Dog*>(animal); // Safe downcasting dog->makeSound(); // Outputs: "The dog barks" dog->wagTail(); // Outputs: "The dog wags its tail"
这个例子中,animal变量本质就是Dog,因此downcasting为Dog类型就可以使用对应的函数。
dynamic_cast
dynamic_cast
主要用于类的downcasting和upcasting。这种cast会在runtime动态检查,在upcasting时,这种是更加安全的操作,效果与static_cast
类似。但是在downcasting时,dynamic_cast
会对其进行安全检查,这时后会访问父类的虚函数表(只有父类定义了虚函数才有虚函数表,有虚函数说明具有父类转换子类的需求和能力),如果没有虚函数表或没找到相关的信息,或者object不是目标类型,动态检查会失败,即返回一个nullptr。
Note:要使用dynamic_cast
,且downcasting时,必须父类拥有虚函数。
下面是使用dynamic_cast
的例子:
class Base {
public:
virtual void foo() {} // Making this class polymorphic
};
class Derived : public Base {
public:
void bar() {}
};
Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
derivedPtr->bar();
}
这个例子中,Base是基类且有虚函数,Derived是派生类。
reinterpret_cast
Reinterpret_cast不会在cast过程中进行安全检查,需要程序员在使用的时候格外小心。理解起来较为方便,首先把某个数据或者object当作内存里的一块01组成的block。接下来,在做reinterpret cast的时候,本质就是在这个block之上加入不同的看待这个block的视角。我可以cast为int,那么使用的时候就被解释为int,我可以cast到一个class,那么使用的时候就被解释为一个class。
给予最大的自由,不加繁琐的限制,至于安全问题交给程序员来操心。
const_cast
🚧(building...)🚧