C++各种强制类型转换

791 阅读2分钟

C++中可以使用C的强制类型转换但是为了更加规范C++制定了四种强转。

1. const_cast

顾名思义,把常量指针和引用强转为非常量指针和引用,强转后变量指向当初的常量对象。这个强转发生在编译的时候。设计这个函数的主要目的是解决某些情况的无奈之举。比如我用一个const引用或者const指针指向一个非const对象,但是后来我又想用这个指针或者引用去改指向的变量就会用到。

int v = 1;
const int* a = &v;
int* b = const_cast<int*>(a);
++(*b);

而用一个const引用指针或者是引用指向一个const变量然后再强转成非const再更改值这种情况就是一个UB

const int v = 1;
const int* a = &v;
int* b = const_cast<int*>(a);
++(*b); // UB

2. static_cast

这个强制类型转换有点类似于C的强制类型转换,在运行时不会对类型的downcast安全性进行检测,但是会做基本的类型检测。这个强转发生在编译的时候。也可以做基本数据类型的强转。比如从char转到int。

class A{
public:    
    int v1;
};
class B : public A{
public:    
    int v2;    
    int v3;
};
B* b = new B();
A* a = static_cast<A*>(b);
// char* c = static_cast<A*>(b); error
//A* a = new A();
//B* b = static_cast<B*>(a); // wrong but can run

3. dynamic_cast

这个强制类型转换与static_cast不同的是会在downcast的时候做安全检测,如果强转失败则会返回对应类型的空指针。由于需要安全监测,所以这个强转发生在运行时,关于runtime的安全检测机制,C++使用了RTTI(runtime type information)来获得相关信息。

#include <iostream>

struct V {
    virtual void f() {};  // must be polymorphic to use runtime-checked dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
  B(V* v, A* a) {
    // casts during construction (see the call in the constructor of D below)
    dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
    dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
  }
};
struct D : A, B {
    D() : B(static_cast<A*>(this), this) { }
};

struct Base {
    virtual ~Base() {}
};

struct Derived: Base {
    virtual void name() {}
};

int main()
{
    D d; // the most derived object
    A& a = d; // upcast, dynamic_cast may be used, but unnecessary
    D& new_d = dynamic_cast<D&>(a); // downcast
    B& new_b = dynamic_cast<B&>(a); // sidecast

    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
    }

    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
    }

    delete b1;
    delete b2;
}

4. reinterprent_cast

这个强制类型转换不做任何的检查,程序员说啥就是啥,这个强转也发生在编译时期。就像名字一样对变量进行重新解释,因此比较危险,使用的时候需要小心。