我一直避免使用C ++演员表({{1}},static_cast
,const_cast
[我也避免使用RTTI]等等)因为我认为它们是浪费打字而我从未见过任何优点,所以我只使用C风格的演员表。
我的问题是,如果你有一个继承层次结构和一个指向基类型的指针,你是否可以安全地使用C风格的转换将基指针强制转换为派生指针(前提是你绝对确定基本指针指向一个派生类型的实例)没有在幕后发生会导致看似无法解释的失败的事情?
我问这个因为我在另一个问题的评论之一中读到,使用从基类到派生类型的C风格转换不会“调整指针”或类似的东西。我会再次尝试找到确切的评论。
答案 0 :(得分:7)
使用static_cast
或dynamic_cast
进行投射可确保某种安全性
如果演员表无效,static_cast
会给你一个编译时错误
dynamic_cast
抛出References的异常,或者在运行时无效的强制转换时返回空指针。
如果你完全确定演员表是有效的,即使是c风格的演员也是如此,但是最好使用提供的语言而不是自己管理(因为我们不需要)。< / p>
答案 1 :(得分:1)
指针(不是引用)的dynamic_cast
使您有机会检测错误并处理它;平原C演员不会。但是,如果你对这些类型非常有把握,那么C风格的演员 - 尽管它是可恶的 - 应该可以正常工作;它是在有C ++标准之前必须工作的。
答案 2 :(得分:1)
如果你的派生类引入了额外的成员,是的,如果你试图将指针上的指针或索引作为数组索引,我认为事情可能会出错。
请考虑以下事项:
class base
{
public:
int _data1;
base () : _data1(0) {}
};
class derived : public base
{
public:
int _data2;
derived () : _data2(1) {}
};
int main ()
{
base *_base_ptr = new derived[10];
// this isn't going to work correctly, because the compiler will use `sizeof(base)`
// to do the pointer offsets, rather than sizeof(derived)...
int _data = _base_ptr[1]._data1;
delete[] _base_ptr;
return _data;
}
在ideone
中运行此代码段会返回1
而不是预期的0
。
希望这有帮助。
答案 3 :(得分:1)
C ++样式转换在模板代码中很重要。在模板代码中,您对来自或转换的对象的类型不太确定,因为这些类型是由用户提供的。如果你最终做了一个不需要的转换(例如在不相关的指针类型之间进行静态转换),C ++样式转换会给你编译器错误,但C样式转换只会执行转换。
例如(琐碎的例子)
template <class T>
T* safe_downcast(Base* ptr)
{
return static_cast<T*>(ptr);
}
如果我使用C风格的演员,那么这个函数没有任何安全性。
但我同意,除了模板代码之外,我经常使用C样式转换。
答案 4 :(得分:0)
如果您完全确定基类指针实际指向派生类型的实例,为什么还有一个基本指针?另外:听起来好像这是虚拟功能的经典案例。如果由于某种原因(性能,...)而想要避免虚拟调用,请查找CRTP。
我使用C ++风格的演员表主要是因为他们提醒我通过看起来丑陋来检查演员是否绝对必要。我尽量避免使用reinterpret_cast和dynamic_cast(大部分时间都是这样),并且我主要在CRTP模板类中使用static_cast,这样就可以了。