将指针指向基类转换为指向派生类的指针

use*_*201 3 c++ casting

我已经阅读了一些关于使用C++进行转换的内容.从C背景的,使用普通的(type)铸造是对于像常见void *但对于C++,有dynamic_cast,reinterpret_cast,static_cast等.

问题/问题/问题是当基指针和派生指针之间的转换时应该使用上述哪些转换.

我们的数据存储存储指向基类(B)的指针.函数分配派生指针(D).

代码示例如下:

class B
{ int _some_data; }
class D : public B
{ int _some_more_data; }
Run Code Online (Sandbox Code Playgroud)

然后代码看起来像:

D *obj = new D;
obj->_some_data = 1;
obj->_some_more_data = 2;
<store obj>
Run Code Online (Sandbox Code Playgroud)

然后我们访问数据时:

B *objB = <get out data>
if (objB->_some_data == 1)
{ D *objD = (D *) objB; <do some processing> }
Run Code Online (Sandbox Code Playgroud)

现在我担心的演员是D *objD = (D *) objB.

我们应该使用哪种演员?

谢谢.

Luc*_*ore 6

在这种情况下,没有演员阵容是真正安全的.

最安全的是dynamic_cast,但你的对象不是多态的,所以它不适用于此.但是你应该考虑至少有一个virtual析构函数,因为我可以看到你计划扩展类.

static_cast正如这个msdn页面所指出的那样是不安全的:

class B {};

class D : public B {};

void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // not safe, pb may
                                   // point to just B

   B* pb2 = static_cast<B*>(pd);   // safe conversion
}
Run Code Online (Sandbox Code Playgroud)

reinterpret_cast 也没有检查,所以不要依赖它.

另外,转换为派生类的指针至少是一种代码气味,如果你需要这样做,99%肯定你有一个有缺陷的设计.


Che*_*Alf 3

对于您了解但编译器不了解的相关类型,请使用static_cast.

但就你而言,你根本不应该铸造。

你这样写

我们的数据存储存储一个指向基类(B)的指针。这些函数分配派生指针 (D)。

那就是丢弃信息,这不是一个好主意。有人意识到这不是一个好主意,实际上它无法工作,因此尝试将该类型信息动态保留在 的值中B::_some_data。总的效果是:放弃对处理该类型信息的C++ 支持,并代之以非常脆弱且肮脏的本土解决方案。

为了利用 C++ 支持,使 B 成为一个多态类,即至少有一个virtual成员:

struct B { virtual ~B() {} };
Run Code Online (Sandbox Code Playgroud)

我删除了数据成员_some_data,因为显然它的唯一目的是跟踪动态类型,现在 C++ 支持实际上是通过对象中所谓的“vtable 指针”来实现这一点。总的对象大小可能是相同的。然而,虫子的吸引力和纯粹的丑陋却减少了几个数量级。;-)

然后,

struct D
    : B
{
    int some_more_data_;
    D( int v ): some_more_data_( v ) {}
};
Run Code Online (Sandbox Code Playgroud)

然后,对于多态类,您的处理代码可以使用 safe dynamic_cast,如下所示:

B* const objB = getOutData();
if( D* const objD = dynamic_cast<D*>( objB ) )
{
    // do some processing using objD
}
Run Code Online (Sandbox Code Playgroud)

现在这种手动动态类型检查仍然很脏并且反映了非OO系统架构。通过面向对象,操作不再检查给定的数据类型,而是数据有效地包含指向适当的专门操作的指针。但我认为最好一次迈出一步,作为第一步:摆脱脆弱的吸引错误的本土动态类型检查方案,并使用相对干净的超级骗子新鲜好闻好看等等。C++对此的支持。:-)