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

  1. Upcasting:Upcasting是将指向子类的指针转化为指向父类的指针,这样的操作在C++中是认为安全的。

    Dog* dog = new Dog();
    Animal* animal = static_cast<Animal*>(dog);  // Upcasting
    animal->makeSound();  // Outputs: "The dog barks"
  2. 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...)🚧