多态允许我们把指向基类的指针可以访问派生类的内容,但是假如我们想访问的派生类中的函数不是重写的基类的虚函数,而是派生类自己的函数呢?
上例子更清楚明白一点:
#include <iostream>
#include <string>
class Base
{
protected:
int m_value;
public:
Base(int value)
: m_value(value)
{
}
virtual ~Base() {}
};
class Derived : public Base
{
protected:
std::string m_name;
public:
Derived(int value, std::string name)
: Base(value), m_name(name)
{
}
const std::string& getName() const { return m_name; }
};
Base* getObject(bool bReturnDerived)
{
if (bReturnDerived)
return new Derived(1, "Apple");
else
return new Base(2);
}
int main()
{
Base *b = getObject(true);
// how do we print the Derived object's name here, having only a Base pointer?
delete b;
return 0;
}
由于返回的指针类型一直都是基类型的指针,在指针指向Derived对象的情况下,我们怎么调用Derived :: getName()
呢?
这时候就是:dynamic_cast
C ++提供了一个名为dynamic_cast
的强制转换运算符,可用于此目的。尽管动态类型转换具有一些不同的功能,但到目前为止,动态类型转换最常见的用途是将基类指针转换为派生类指针。此过程称为向下转换。
改写函数为:
int main()
{
Base *b = getObject(true);
Derived *d = dynamic_cast<Derived*>(b); // use dynamic cast to convert Base pointer into Derived pointer
std::cout << "The name of the Derived is: " << d->getName() << '\n';
delete b;
return 0;
}
将打印:
The name of the Derived is: Apple
防止转换失败
但是,我们做出了一个非常危险的假设:b指向派生对象。如果b没有指向派生对象怎么办?通过将getObject()的参数从true更改为false,可以轻松地进行测试。在这种情况下,getObject()将返回指向基础对象的基础指针。当我们尝试将其动态转换为“派生”时,它将失败,因为无法进行转换。
如果dynamic_cast失败,则转换结果将为空指针。
因为我们没有检查空指针结果,所以我们访问d-> getName(),它将尝试取消引用空指针,从而导致未定义的行为(可能是崩溃)。
为了使该程序安全,我们需要确保dynamic_cast的结果实际上是成功的:
int main()
{
Base *b = getObject(true);
Derived *d = dynamic_cast<Derived*>(b); // use dynamic cast to convert Base pointer into Derived pointer
if (d) // make sure d is non-null
std::cout << "The name of the Derived is: " << d->getName() << '\n';
delete b;
return 0;
}
①始终通过检查空指针结果来确保动态转换真正成功。
②请注意,由于dynamic_cast在运行时会进行一些一致性检查(以确保可以进行转换),因此使用dynamic_cast会导致性能下降。