从 Parent 到 Child 需要什么样的演员表?
What Type of Cast to Go from Parent to Child?
这个问题是关于应该使用哪个 C++ style cast 来进行这种转换。我知道 C 风格转换可以实现这一点。
对于以下 class
结构:
class Foo {};
class Bar : public Foo {};
假设我得到:Foo* ptr;
,我想将其转换为 Bar*
我应该使用哪种类型的转换?看来我必须按原样使用 dynamic_cast
:
Used for conversion of polymorphic types
我想避免 dynamic_cast
因为它是 运行 时间转换。
您说得对,dynamic_cast
通常最适合这种情况。但是,如果您知道 指针实际上指向派生class 的对象,则可以使用static_cast
进行转换。如果你错了并且指针是 而不是 派生的 class,你将得到未定义的行为。
static_cast
只要您确定要转换的对象确实是您期望的类型,就可以正常工作。根据你给出的例子,看起来你很确定。
为了清楚起见:
I wanted to avoid dynamic_cast
since it is a run time cast.
好吧,你有一个 运行-time 类型(给定一个静态类型的基类引用-class,你不能一般知道对象的动态类型),因此 运行 时间转换是唯一完全安全的选择。
如果你认为你的对象真的是一个 Bar
,但你错了,dynamic_cast<Bar*>
会给你一个 nullptr
,或者 dynamic_cast<Bar&>
会抛出一个异常。无论哪种方式,您都有机会在 运行 时间处理您的 运行 时间错误。正如 M.M 所指出的,这仅在您的基础 class 具有或继承至少一个虚拟方法时才可用。
现在,如果碰巧你可以静态地确定你的对象的动态类型真的是 Bar
,你可以使用 static_cast
。但是,如果你弄错了,你就会有未定义的行为并且没有机会检测或处理错误。
例如
struct Foo { virtual ~Foo(){} };
struct Bar : public Foo {};
// safe, may return nullptr
Bar* safe_ptr_cast(Foo *f) { return dynamic_cast<Bar*>(f); }
// safe, may throw but you can catch it
Bar& safe_ref_cast(Foo &f) { return dynamic_cast<Bar&>(f); }
// unsafe - if you're wrong, you just broke everything
Bar* unsafe_ptr_cast(Foo *f) { return static_cast<Bar*>(f); }
顺便说一下,如果 运行 时间转换的问题是性能问题,那么在您对代码进行概要分析之前冒着 UB 的风险来节省名义时间就是过早优化的定义。
这个问题是关于应该使用哪个 C++ style cast 来进行这种转换。我知道 C 风格转换可以实现这一点。
对于以下 class
结构:
class Foo {};
class Bar : public Foo {};
假设我得到:Foo* ptr;
,我想将其转换为 Bar*
我应该使用哪种类型的转换?看来我必须按原样使用 dynamic_cast
:
Used for conversion of polymorphic types
我想避免 dynamic_cast
因为它是 运行 时间转换。
您说得对,dynamic_cast
通常最适合这种情况。但是,如果您知道 指针实际上指向派生class 的对象,则可以使用static_cast
进行转换。如果你错了并且指针是 而不是 派生的 class,你将得到未定义的行为。
static_cast
只要您确定要转换的对象确实是您期望的类型,就可以正常工作。根据你给出的例子,看起来你很确定。
为了清楚起见:
I wanted to avoid
dynamic_cast
since it is a run time cast.
好吧,你有一个 运行-time 类型(给定一个静态类型的基类引用-class,你不能一般知道对象的动态类型),因此 运行 时间转换是唯一完全安全的选择。
如果你认为你的对象真的是一个 Bar
,但你错了,dynamic_cast<Bar*>
会给你一个 nullptr
,或者 dynamic_cast<Bar&>
会抛出一个异常。无论哪种方式,您都有机会在 运行 时间处理您的 运行 时间错误。正如 M.M 所指出的,这仅在您的基础 class 具有或继承至少一个虚拟方法时才可用。
现在,如果碰巧你可以静态地确定你的对象的动态类型真的是 Bar
,你可以使用 static_cast
。但是,如果你弄错了,你就会有未定义的行为并且没有机会检测或处理错误。
例如
struct Foo { virtual ~Foo(){} };
struct Bar : public Foo {};
// safe, may return nullptr
Bar* safe_ptr_cast(Foo *f) { return dynamic_cast<Bar*>(f); }
// safe, may throw but you can catch it
Bar& safe_ref_cast(Foo &f) { return dynamic_cast<Bar&>(f); }
// unsafe - if you're wrong, you just broke everything
Bar* unsafe_ptr_cast(Foo *f) { return static_cast<Bar*>(f); }
顺便说一下,如果 运行 时间转换的问题是性能问题,那么在您对代码进行概要分析之前冒着 UB 的风险来节省名义时间就是过早优化的定义。