CPP新式转型

Type Casting

dynamic_cast

用于父类和子类之间的转换(一般是父类向子类的安全向下转)

dynamic_cast can be used only with pointers and references to objects. Its purpose is to ensure that the result of the type conversion is a valid complete object of the requested class. (注意:适用于指针或引用;转换必须完整)

RTTI (Run-time type Information) in C++

  • 派生类到基类的转换
    • 因为派生类中含有基类part,所以派生类可以完整转到基类
#include<iostream>
using namespace std;
class B { };
class D: public B { };

int main()
{
    B *pb;
    D d; D *pd;
//    成功转换
    pb=dynamic_cast<B*> (&d);
    cout<<((pb!=nullptr)? "success": "cannot cast")<<endl;
//    成功转换
    pb=dynamic_cast<B*> (pd);
    cout<<((pb!=nullptr)? "success": "cannot cast")<<endl;
}
  • 基类到派生类的转换
    • 基类带有多态属性时(即:基类中有virtual性质的成员函数),且能实现完整转换(即:基类的指针指向的是派生类的对象,如CBase * pba = new CDerived;)时,才能成功转换
// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;
//基类中有virtual性质的成员函数
class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };

int main () {
    try {
//        基类指针pba指向派生类对象,可以完整转换
        CBase * pba = new CDerived;
//        基类指针pbb指向基类对象,不能完整转换
        CBase * pbb = new CBase;
        CDerived * pd;
//        实现完整转换,成功
        pd = dynamic_cast<CDerived*>(pba);
        if (pd==0) cout << "Null pointer on first type-cast" << endl;
//        不能实现完整转换
        pd = dynamic_cast<CDerived*>(pbb);
        if (pd==0) cout << "Null pointer on second type-cast" << endl;

    } catch (exception& e) {cout << "Exception: " << e.what();}
    return 0;
}

static_cast

  • static_cast can perform conversions between pointers to related classes, not only from the derived class to its base, but also from a base class to its derived. This ensures that at least the classes are compatible if the proper object is converted, but no safety check is performed during runtime to check if the object being converted is in fact a full object of the destination type. (实现基类与派生类的互相转换,但是没有安全检查,可能运行时会出错。如下面的代码,实现的是不完整的转换)
// This would be valid, although b would point to an incomplete object of the class and could lead to runtime errors if dereferenced.
class CBase {};
class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast<CDerived*>(a);
  • static_cast can also be used to perform any other non-pointer conversion that could also be performed implicitly, like for example standard conversion between fundamental types (也可以用于基本类型的转换,如double转int)

reinterpret_cast

  • reinterpret_cast converts any pointer type to any other pointer type, even of unrelated classes.
  • It can also cast pointers to or from integer types.

const_cast

const_cast manipulates the constness of an object, either to be set or to be removed. 可以把对象的常量属性去除
const_cast< here> 中,here必须是a reference, pointer-to-object, or pointer-to-data-member

// 去除常量属性,实现+1运算
// const_cast
#include <iostream>
using namespace std;

void print (int* i)
{
    *i+=1;
    cout << *i << endl;
}

int main () {
    int i=10;
    const int *pi = &i;
    //只有通过const_cast把const属性去掉后,才能*i+=1;
    print ( const_cast<int *> (pi) );  // 11
    return 0;
}
// const_cast
#include <iostream>

using namespace std;

void print(const int i) {
    int j = const_cast<int &>(i);
    j += 1;
    cout << j << endl;
}

int main() {
    const int i = 10;
    print(i);
    return 0;
}

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn’t necessary, but it’s important to note that the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn’t cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn’t actually the type of the object.


const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn’t declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.

const_cast also works similarly on volatile, though that’s less common.


dynamic_cast is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can’t, it will return nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast has some limitations, though. It doesn’t work if there are multiple objects of the same type in the inheritance hierarchy (the so-called ‘dreaded diamond’) and you aren’t using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.


reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast cannot do, too. It’s used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.

effective c++ P117

  • 有相同派生类的基类指针转换
#include <iostream>
#include <cmath>
using namespace std;

struct A1{
    virtual ~A1(){}
};
struct A2{
    virtual ~A2(){}
};
struct B1 : A1, A2{};
int main()
{
    B1 d;
    A1* pb1 = &d;
    A2* pb2 = dynamic_cast<A2*>(pb1);  //L1
    cout<<(pb2!=0)<<endl; // 有相同派生类的基类 可以转换成功 

//    Static_cast from 'A1 *' to 'A2 *', which are not related by inheritance, is not allowed
//    A2* pb22 = static_cast<A2*>(pb1);  //L2
}

   转载规则


《CPP新式转型》 M 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录