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

时间:2012-02-21 08:22:44

标签: c++ casting

我已经阅读了一些关于使用C ++进行转换的内容。来自C背景,使用普通(type)强制转换对void *之类的内容很常见,但对于C ++,有dynamic_castreinterpret_caststatic_cast等。

问题/问题/问题是在基指针和派生指针之间进行转换时应该使用上述哪些转换。

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

代码示例如下:

class B
{ int _some_data; }
class D : public B
{ int _some_more_data; }

然后代码看起来像:

D *obj = new D;
obj->_some_data = 1;
obj->_some_more_data = 2;
<store obj>

然后我们访问数据时:

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

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

我们应该使用哪种演员?

感谢。

3 个答案:

答案 0 :(得分: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
}

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

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

答案 1 :(得分:3)

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

但在你的情况下,你根本不应该投。

你写的那个

  

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

这是丢弃信息,这不是一个好主意。有人意识到这不是一个好主意,实际上它无法工作,因此试图将该类型信息动态保存在B::_some_data的值中。总效果:抛弃 C ++支持来处理该类型信息,并替换一个非常脆弱和肮脏的本土解决方案。

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

struct B { virtual ~B() {} };

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

然后,

struct D
    : B
{
    int some_more_data_;
    D( int v ): some_more_data_( v ) {}
};

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

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

现在,这种手动动态类型检查仍然非常脏,反映了非OO系统架构。使用对象取向,而不是操作检查它们被赋予了什么类型的数据,数据有效地包含指向适当的专门操作的指针。但我认为最好一步一步,作为上面的第一步:摆脱脆弱的虫子 - 吸引本土的动态类型检查方案,并使用相对干净的超级duper新鲜美味的好看等等.C ++支持。 : - )

答案 2 :(得分:0)

在这种情况下,您应该使用dynamic_cast