How to use c++ type conversion (static_cast, const_cast, dynamic_cast, reinterpret_cast)

Why use C++ style type conversion

We all know that C++ type conversion can use either C-style type conversion, such as (type)expression, or C++-style type conversion. C-style conversion is basically a universal conversion. Types that do not want to interfere with each other can be converted. Base classes Pointers to subclass pointers can also be converted. It's basically a different soup and a different medicine. I remember seeing an example somewhere where a structure pointer was directly converted to an int pointer and then output. I was dumbfounded at the time. There is actually such an operation:

struct Node {
    
    
    int x; // 
    Node* next;
    Node() : x(-1), next(nullptr){
    
    }
};
int main()
{
    
    
    Node* testNode = new Node;
    int* p = (int*)testNode;
    delete testNode;
    return 0;
}

Of course, there is no problem in compiling and running, and dereferencing p can get the value -1, but as long as I change the first line of the structure to the variable string str, then I cannot get the node data through this conversion, so we should be honest when writing code. Act according to the specifications, and don't be opportunistic, otherwise when a bug occurs, it will really be called "Tian Tian Ying", "Tian Tian Ying Ying", "Tian Tian Ying Ying", "Tian Tian Ying Ying", "Tian Tian Ying Ying", "Tian Tian Ying Ying", "Tian Tian Ying Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Tian Ying Tian Ying Tian Ying Tian Ying Tian Ying Tian Tian Ying Tian Ying Tian Ying Tian Ying Tian Tian Ying Tian Tian Ying Tian Tian Ying Tian Tian Ying Tian Tian Ying Tian Tian Ying Tian Tian Yin Tian Tian Y t. It is difficult to identify in the code, and it is quite difficult to identify whether type conversion is used when using code analysis tools.

4 types of transformations

  • static_cast: The function is basically the same as c-style conversion, but there are exceptions. It cannot convert struct into int type or double type into pointer type, nor can it remove the const attribute of expression.
  • const_cast: The only function is to remove the const or volatile attribute of the expression.
  • dynamic_cast: Convert a base class pointer or reference into a subclass pointer, sibling pointer or reference, and convert downward along the inheritance relationship. If the conversion is not of the derived class type, the conversion fails and returns a null pointer (for pointer conversion) or throws an exception (for reference conversion). It can only be used on objects with virtual functions, otherwise a compilation error will be reported.
  • reinterpret_cast: This is really a wild horse running wild. Unless it is absolutely necessary, it will get burned. This is a powerful type conversion that can be used for any type of pointer or reference conversion, and can also be used for pointer to integer, integer to pointer. Convert. For example: you can convert a function pointer int (*fptr)() to void (*fptr)() and remove the return value, or convert an int type to int(*fptr)(). The FAQ page of Bjarne Stroustrup, the father of C++, and MSDN's Visual C++ also pointed out that incorrect use of reinterpret_cast can easily lead to program insecurity. Only by converting the converted type value back to its original type can the reinterpret_cast method be used correctly. .

Quick practice

#include<iostream>
#include<string>
class Poultry {
    
     // 自定义测试类型 家禽类
public:
    Poultry(const std::string& dogName) : m_name(dogName) {
    
    }
    virtual const std::string& GetName() const = 0; // 一般来说家禽类不给实例化,哈哈
    virtual ~Poultry() {
    
    };
protected:
    std::string m_name;
};

// dog也是家禽的一种,但我们得把野狗排除一下,这儿没有野狗
class Dog :public Poultry {
    
    
    // ...
public:
    Dog(const std::string &dogName) : Poultry(dogName) {
    
    }
    virtual const std::string& GetName() const override
    {
    
     
        return m_name;
    }
};

class SpotDog : public Dog {
    
     // 这是一种带斑点得家禽狗,俗称家禽斑点狗
public:
    SpotDog(const std::string& dogName) : Dog(dogName) {
    
    }
    virtual const std::string& GetName() const override
    {
    
     
        return m_name; 
    }
};

void FooDog(Poultry *poultry) // 测试函数
{
    
    
    // 传入指针,使其发生动态绑定
    // ... do something
}

void FooSpotDog(SpotDog* spotDog)
{
    
    
    // ... do something
}

void Foo() {
    
     /* ...*/ } // 函数
typedef void(*FooPtr)(); // 函数指针
int FooInt() {
    
     return 0; } // 函数
typedef int(*FooIntPtr)(); // 又一个函数指针

int main(int argc, char *agrv[])
{
    
    
    Poultry *dog = new Dog("小黑"); // 一只狗
    // 某些狗出生就有名字了,比如总是小黑小黑的叫,某一天你叫它小白,它就听不懂了
    const Poultry* constDog = dog; 
    FooDog(constDog); // 错误 函数接收一个Pooultry*
    FooDog(static_cast<Poultry*>(constDog)); // 错误  static_cast 只能去掉常量属性
    FooDog(dynamic_cast<Poultry*>(constDog)); // 错误 不能去掉常量属性,仅仅使用于继承类链的向下转换
    FooDog(const_cast<Poultry*>(constDog)); // 正确 const_cast 专门用来去掉常量属性的
    Dog* spotDog = new SpotDog("斑点狗");
    FooSpotDog(const_cast<SpotDog*>(spotDog)); // 失败,只能去掉const属性,再无别的用途
    FooSpotDog(static_cast<SpotDog*>(spotDog)); // 成功,但是不好,没有转换失败
    FooSpotDog(reinterpret_cast<SpotDog*>(spotDog)); // 成功,但是不好,没有提示转换失败,而且这个转换很野
    FooSpotDog(dynamic_cast<SpotDog*>(spotDog)); // 成功,最佳选择,如果转换失败是会返回空指针的,
    int b = 0;
    double d = dynamic_cast<double>(b) / 5.0; // 错误,double没有虚函数 没有继承系统
    // 最后来看看reinterpret_cast的用法,一个字,野
    FooIntPtr funFooInt = &FooInt;
    FooPtr funFoo = reinterpret_cast<FooPtr>(funFooInt); // ok 任何指针都可以转换
    funFooInt = reinterpret_cast<FooIntPtr>(funFoo); // ok 
    int* fun = reinterpret_cast<int*>(funFoo); // ok
    int* funInt = reinterpret_cast<int*>(funFooInt); // ok
    funFooInt = reinterpret_cast<FooIntPtr>(fun); // ok
    funFoo = reinterpret_cast<FooPtr>(funInt); // 统统都ok,一个字,干就完了。
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_33944628/article/details/118035536