static_cast和dynamic_cast

  • Post category:C++

C++的强制类型转换,除了继承自C语言的写法((目标类型)表达式)之外,还新增了4个关键字,分别是:static_castdynamic_castconst_castreinterpret_cast。用法:xxx_cast<目标类型>(表达式)。由于后两者的使用频率较少,尤其是reinterpret_cast的风险性很高,所以就不展开讲了。这里主要将static_castdynamic_cast

static_cast

解释

所谓static_cast,顾名思义,就是静态的转换,是在编译期间就能确定的转换。

主要用途

  1. 用于基本数据类型之间的转换。
#include <iostream>

using namespace std;

int main()
{
    float f = 5.67;
    auto i = static_cast<int>(f);
    cout << i << endl;  // 输出结果:5
    return 0;
}
  1. 用于有转换关系的类之间的转换。
#include <iostream>

using namespace std;

class Src
{
public:
    void foo()
    {
        cout << "This is Src" << endl;
    }
};

class Dest
{
public:
    /** 类型转换构造函数 */
    Dest(const Src &from)
    {
        cout << "Converting from Src to Dest" << endl;
    }

    void foo()
    {
        cout << "This is Dest" << endl;
    }
};

int main()
{
    Src src;
    auto dst = static_cast<Dest>(src);  // 输出结果:Converting from Src to Dest
    dst.foo();  // 输出结果:This is Dest
}
  1. 用于在类继承体系中指针或引用上行转换(即派生类到基类的转换)。如果用作下行转换(即基类到派生类的转换),由于不会动态的检查指针或引用是否真正指向派生类对象,因此不安全,要用到稍后要讲的dynamic_cast
#include <iostream>

using namespace std;

class Base
{
public:
    void foo()
    {
        cout << "This is Base" << endl;
    }
};

class Derived : public Base
{
public:
    void foo()
    {
        cout << "This is Derived" << endl;
    }
};

void test_upcast()
{
    Derived derived;
    Derived *pDerived = &derived;
    auto pBase = static_cast<Base *>(pDerived);
    pBase->foo();  // 输出结果:This is Base
}

void test_downcast()
{
    Base base;
    Base *pBase = &base;
    auto pDerived = static_cast<Derived *>(pBase);  // 不安全:pa并没有真正指向B类对象
    pDerived->foo();  // 输出结果:This is Derived。这里虽然输出了结果,但是不安全
}

int main()
{
    test_upcast();
    test_downcast();
    return 0;
}

dynamic_cast

解释

所谓dynamic_cast,顾名思义就是动态的转换,是一种能够在运行时检查安全性的转换。

使用条件:

  1. 基类必须有虚函数。
  2. 只能转引用或指针。

主要用途

用于继承体系中的上行或下行转换。上行转换跟static_cast是一样的;下行转换会在运行时动态判断。如果目标类型并没有指向对象的实际类型,那么:

  1. 指针的转换会返回nullptr
  2. 引用的转换会抛出std::bad_cast异常
#include <iostream>

using namespace std;

class Base
{
public:
    virtual void foo()
    {
        cout << "This is Base" << endl;
    }
};

class Derived : public Base
{
public:
    void foo() override
    {
        cout << "This is Derived" << endl;
    }
};

/** Derived * -> Base * */
void test_upcast_ptr()
{
    Derived derived;
    Derived *pDerived = &derived;
    auto base = dynamic_cast<Base *>(pDerived); // 尝试将派生类指针转换为基类指针
    if (base)
    {
        cout << "Derived * -> Base * was successful" << endl;
    }
    else
    {
        cout << "Derived * -> Base * failed" << endl;
    }
}

/** Base * -> Derived * */
void test_downcast_ptr1()
{
    Derived derived;
    Base *pBase = &derived; // 基类指针指向派生类对象
    auto pDerived = dynamic_cast<Derived *>(pBase); // 尝试将指向派生类对象的基类指针转换为派生类指针
    if (pDerived)
    {
        cout << "Base * -> Derived * was successful" << endl;
    }
    else
    {
        cout << "Base * -> Derived * failed" << endl;
    }
}

/** Base * -> Derived * */
void test_downcast_ptr2()
{
    Base base;
    Base *pBase = &base;
    auto derived = dynamic_cast<Derived *>(pBase); // 尝试将指向基类对象的基类指针转换为派生类指针
    if (derived)
    {
        cout << "Base * -> Derived * was successful" << endl;
    }
    else
    {
        cout << "Base * -> Derived * failed" << endl;
    }
}

/** Derived & -> Base & */
void test_upcast_ref()
{
    Derived derived;
    Derived &refDerived = derived;
    try
    {
        auto &base = dynamic_cast<Base &>(refDerived); // 尝试将派生类引用转换为基类引用
        cout << "Derived & -> Base & was successful" << endl;
    }
    catch (bad_cast &)
    {
        cout << "Derived & -> Base & failed" << endl;
    }
}

/** Base & -> Derived & */
void test_downcast_ref1()
{
    Derived derived;
    Base &refBase = derived; // 基类引用指向派生类对象
    try
    {
        auto &refDerived = dynamic_cast<Derived &>(refBase); // 尝试将指向派生类对象的基类引用转换为派生类引用
        cout << "Base & -> Derived & was successful" << endl;
    }
    catch (bad_cast &)
    {
        cout << "Base & -> Derived & failed" << endl;
    }
}

/** Base & -> Derived & */
void test_downcast_ref2()
{
    Base base;
    Base &refBase = base;
    try
    {
        auto &refDerived = dynamic_cast<Derived &>(refBase); // 尝试将指向基类对象的基类引用转换为派生类引用
        cout << "Base & -> Derived & was successful" << endl;
    }
    catch (bad_cast &)
    {
        cout << "Base & -> Derived & failed" << endl;
    }
}

int main()
{
    test_upcast_ptr();     // Derived * -> Base * was successful
    test_downcast_ptr1();  // Base * -> Derived * was successful
    test_downcast_ptr2();  // Base * -> Derived * failed
    test_upcast_ref();     // Derived & -> Base & was successful
    test_downcast_ref1();  // Base & -> Derived & was successful
    test_downcast_ref2();  // Base & -> Derived & failed
}