2012-02-21 159 views
3

我已经阅读了关于在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

我们应该使用哪一种?

谢谢。

+0

在这种情况下,dynamic_cast。它将检查该对象是否可以在运行时转换为D *。 – BoBTFish 2012-02-21 08:25:49

+3

@BoBTFish'dynamic_cast'只适用于多态类型。 – 2012-02-21 08:30:32

回答

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系统架构。通过对象定位,数据不是检查给定数据的操作,而是有效地包含指向适当专用操作的指针。但我认为最好一次采取一步,作为上述第一步:摆脱吸收脆弱的臭虫的本土动态类型检查方案,并使用相对干净的超级爽快新鲜美观的好看等C++的支持。 :-)

+0

谢谢 - _some_data被用来传达比以上更多的信息,但我明白了。然而,我并没有遵循'使用对象概念,而不是操作来检查它们已经给出了什么类型的数据,数据有效地包含指向适当的专门操作的指针。这是否意味着基类包含所有可能操作的虚函数?谢谢。 – user626201 2012-02-21 09:07:27

+1

不,它不需要“包含所有可能的操作的虚拟功能”。明显的需求是设计气味,但是,当这种明显的需求弹出时,什么是实用的解决方案?那么,这是一个非常常见的问题,它应该是一个常见问题解答,答案是“访问者模式”。在这里解释太多,但实际上,您会向访问者发送知道类型的代码。然后,该代码可以回访专门处理给定类型的访问者部分。 – 2012-02-21 09:10:20

+0

谢谢 - 我会查找模式 - 从来没有听说过它。 – user626201 2012-02-21 09:29:38

0

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

+0

+1以对抗无法解释的ungood downvote。 – 2012-02-21 08:28:42

+1

@ Cheersandhth.-Alf'dynamic_cast'不起作用,因为他的类不是多态的。 – 2012-02-21 08:29:27

+0

@干杯和hth。 - Alf,谢谢 – Sergey 2012-02-21 08:32:07

6

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

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

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%肯定你有一个有缺陷的设计。

+0

你为什么说他的物体不是多态的?它们来自对方...我会同意缺少虚拟析构函数tho。 – RedX 2012-02-21 08:30:06

+1

'static_cast'将是合法的,并且做他想做的事(但我同意你的分析,唯一的好的解决方案是使对象变为多态并使用'dynamic_cast')。 – 2012-02-21 08:30:28

+0

@RedX在C++中,如果至少有一个虚拟函数,则只能将对象类型视为多态。继承是一种实现技术,可以用于不同的目的,而不仅仅是多态。 (我认为任何人都不会认为迭代器是多态的,只是因为它来自'std :: iterator'。) – 2012-02-21 08:32:26

相关问题