我一直避免使用c++类型转换(static_cast
, const_cast
, dynamic_cast
[我也避免使用RTTI]等),因为我认为它们浪费了输入,而且我从未看到任何优点,所以我只使用C风格的类型转换。
我的问题是,如果你有一个继承层次结构和一个指向基类型的指针,你能安全地将基指针强制转换为具有c风格强制转换的派生指针(只要你绝对确定基指针指向派生类型的实例),而不会在幕后发生一些事情,导致看似无法解释的失败吗?
我问这个问题是因为我在另一个问题的评论中读到,使用c风格的从基类型到派生类型的强制转换不会"调整指针"或类似的东西。
使用static_cast
或dynamic_cast
进行浇注,有一定的安全性。
如果强制转换无效,static_cast
会给你一个编译时错误,dynamic_cast
在运行时抛出引用异常或在无效强制转换的情况下返回空指针。
因此,它们比c风格的强制类型要好,主要是因为它们提供了安全性。
如果你绝对确定强制转换是有效的,即使是c风格的强制转换也会做同样的事情,但最好使用语言提供的安全性,而不是自己管理它(因为我们不需要)。
一个dynamic_cast
指向一个指针(不是一个引用)给你一个机会来检测错误并处理它;普通的C型则不会。但是,如果你对类型有绝对的把握,那么c风格的强制转换——尽管很糟糕——应该没问题;
如果你的派生类引入了额外的成员,是的,我认为如果你试图索引指针或指针上的索引作为数组,事情可能会出错。
考虑以下内容:
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
。
c++样式强制转换在模板代码中很重要。在模板代码中,我们不太确定要转换的对象的类型,因为这些类型是由用户提供的。如果你最终做了一个不需要的强制转换(例如不相关指针类型之间的静态强制转换),c++风格的强制转换会给你编译器错误,但C风格的强制转换无论如何都会进行强制转换。
例如(小例子)
template <class T>
T* safe_downcast(Base* ptr)
{
return static_cast<T*>(ptr);
}
如果我使用C风格强制转换,那么这个函数就不安全了。
但是我同意,在模板代码之外,我经常使用C风格强制转换
如果您绝对确定基类指针实际上指向派生类型的实例,为什么还要使用基类指针呢?另外:这听起来好像是虚函数的经典案例。如果出于某些原因(性能,…),您希望避免虚拟调用,请查找CRTP。
我使用c++风格的强制转换,主要是因为它们提醒我检查强制转换是否绝对必要。如果可能的话,我尽量避免reinterpret_cast和dynamic_cast(大多数时候是这样的),并且我主要在CRTP模板类中使用static_cast,在那里它是OK的。