基类型静态向下转换为派生类型的问题 [英] Problem with static downcast of base type to derived type

查看:69
本文介绍了基类型静态向下转换为派生类型的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个崩溃的程序:


1 - 我使用static_cast将基本类型指针转换为指向

派生类型的指针


2 - 我使用这个新指针来调用

派生类型的对象中的函数


3 - 这个函数然后''增长''派生类型对象(通过将

推到一个向量上)。


这实际上是否可行,或者我应该是做别的什么?在

更详细,我正在做的是(下面有一个完整的测试程序,

崩溃):


1 - 我有一个不太做的基类;


2 - 我声明了一个派生类,其基础是公共继承

class;


3 - 派生类有一个方法可以推送到

派生类中的向量;


4 - 我创建了一组STL基类对象;


5 - 然后我将派生类的对象插入到此集合中。我使用

设置''insert''方法,它返回一个迭代器到集合中的新对象

,但这是* base *对象的迭代器(我希望)


6 - 我将迭代器转换为指针,并将指针static_cast $ / b $ b转换为指向派生类对象的指针


7 - 我通过这个指针调用我的新方法,将

中的向量推送到derived-class-object。 Bang。


非常感谢。


谢谢 -


Dom


========================================== =

#include< vector>

#include< set>

#include< iostream>

使用std :: vector;

使用std :: set;

使用std :: cout;


级A {

公开:

A(int v):

val(v){}

int val;

};


D级:公开A {

public:

D (int v):

A(v){}


可变向量< intvec;


void dfunc (void)const {

std :: cout<< 你好世界 << val<< "!\ n";

// ******************************** ************

//没有这条线就行了,用这条线撞坏了

vec.push_back(val);

// ********************************************

}

};


class ALess {

public:

bool operator()(const A& a1,const A& a2)const {

return a1.val< a2.val;

}

};


typedef set< A,ALess ASet;

typedef ASet :: iterator ASetIter;

typedef std :: pair< ASetIter,bool ASetInsRetVal;


int main(){

ASetInsRetVal retval;

ASet aset;


for(int i = 0; i< 4; i ++){

retval = aset.insert(D(i));

if(!retval.second)

cout<< insert failed\\\
;

else {

const D * dptr = static_cast< const D *>(&(* retval.first));

dptr-> dfunc(); //崩溃 - 见上面

}

}

}

========= =====================================

解决方案

在2008-07-02 21:13,Dom Jackson写道:


我有一个程序崩溃时:


1 - 我使用static_cast将基本类型指针转换为指向

派生类型的指针


2 - 我使用这个新的指针调用

派生类型的对象中的函数


3 - 这个函数然后''增长''派生类型对象(通过将
推到矢量上。


这实际上是可行的吗,还是我应该做其他事情?在

更详细,我正在做的是(下面有一个完整的测试程序,

崩溃):


1 - 我有一个不太做的基类;


2 - 我声明了一个派生类,其基础是公共继承

class;


3 - 派生类有一个方法可以推送到

派生类中的向量;


4 - 我创建了一组STL基类对象;


5 - 然后我将派生类的对象插入到此集合中。我使用

设置''insert''方法,它返回一个迭代器到集合中的新对象

,但这是* base *对象的迭代器(我希望)


6 - 我将迭代器转换为指针,并将指针static_cast $ / b $ b转换为指向派生类对象的指针


7 - 我通过这个指针调用我的新方法,将

中的向量推送到derived-class-object。砰。



这不起作用,std :: set保存了作为

参数给出的类型的对象,在这种情况下是base-objects和不是派生对象,

派生对象将被切成基础对象。所以你在做什么

试图调用一个不存在的函数来操纵一个不存在的向量




为了解决你的问题,你可以使用一组指针来代替基础(例如std :: set< Base *而不是std :: set< Base>)和

使用new创建对象(例如set.insert(new Derived());)。

除此之外,当从基础转换为派生时,你应该使用

dynamic_cast并检查转换是否成功(在这种情况下返回的

指针将为非0)。如果你在你的代码中这样做,你会发现

你将总是得到一个0指针。只有当指向的对象是

派生的类型时,才允许从指向基类的指针转换为导出的
指针。


你总是可以使用

static_cast从指针派生到指向基础的指针,但是当你走另一条路时你将使用dynamic_cast。


- -

Erik Wikstr ?? m


7月2日下午4:31,Erik Wikstr?m< Erik-wikst ...... @ telia.comwrote:


你总是可以使用

static_cast从指针派生到指向基础的指针,但是当走另一条路时你应该使用dynamic_cast。



" Shall"这里可能有点强。有些情况下,由于

的背景,向下转换不能失败。在这种情况下,使用动态演员

给你

除了性能不好之外什么都没有。


你可以有一个单独的功能,在
调试中使用动态强制转换

但在发布时恢复为静态强制转换,除非

动态强制转换

实际上是设计的一部分(例如类型开关,但是这些

应该是

尽可能避免)。


-

Jonathan Mcdougall


评论内联:

Dom Jackson< no **** @ mci2000.com写在

新闻:6q ******************************** @ 4ax。 com:


我有一个崩溃的程序:



[snip ..代码更多有趣的]


任何帮助非常感谢。


谢谢 -


Dom


====================================== =====
#include< vector>

#include< set>

#include< iostream>


使用std :: vector;

使用std :: set;

使用std :: cout;


class一个{

公开:

A(int v):

val(v){}

int val ;

};


D级:公开A {

public:

D(int v):

A(v){}


可变向量< intvec;


void dfunc(void )const {

std :: cout<< 你好世界 << val<< "!\ n";

// ******************************** ************

//没有这条线就行了,用这条线撞坏了

vec.push_back(val);

// ********************************************

}

};


class ALess {

public:

bool operator()(const A& a1,const A& a2)const {

return a1.val< a2.val;

}

};


typedef set< A,ALess ASet;

typedef ASet :: iterator ASetIter;

typedef std :: pair< ASetIter,bool ASetInsRetVal;


int main(){

ASetInsRetVal retval;

ASet aset;


for(int i = 0; i< 4; i ++){

retval = aset.insert(D(i));



这会将临时D对象切分为A对象。 ASet包含类型A的
对象,并且只有A类型。


if(!retval.second)

cout<< insert failed\\\
;

else {

const D * dptr = static_cast< const D *>(&(* retval.first));



未定义的行为。 retval-> first是A对象。你那么你b $ b迫使编译器试图像D对象那样对待它......


dptr-> dfunc(); //崩溃 - 见上面



....特别是当你试图访问仅存在于

D对象中的成员时。 />


}

}

}

========= =====================================



I have a program which crashes when:

1 - I use static_cast to turn a base type pointer into a pointer to a
derived type

2 - I use this new pointer to call a function in an object of the
derived type

3 - this function then ''grows'' the derived type object (by pushing
onto a vector).

Is this actually possible, or should I be doing something else? In
more detail, what I''m doing is (there''s a complete test program below,
which crashes):

1 - I have a base class which doesn''t do very much;

2 - I declare a derived class with public inheritance from the base
class;

3 - the derived class has a method which pushes onto a vector in the
derived class;

4 - I create an STL set of base class objects;

5 - I then insert an object of the derived class into this set. I use
the set ''insert'' method, which returns an iterator to the new object
in the set, but this is an iterator to a *base* object (I hope)

6 - I convert the iterator to a pointer, and static_cast the pointer
to a pointer to an object of the derived class

7 - I call my new method via this pointer, pushing onto the vector in
the derived-class-object. Bang.

Any help much appreciated.

Thanks -

Dom

===========================================
#include <vector>
#include <set>
#include <iostream>

using std::vector;
using std::set;
using std::cout;

class A {
public:
A(int v) :
val(v) {}
int val;
};

class D : public A {
public:
D(int v) :
A(v) {}

mutable vector<intvec;

void dfunc(void) const {
std::cout << "hello world " << val << "!\n";
// ********************************************
// Ok without this line, crashes with this line
vec.push_back(val);
// ********************************************
}
};

class ALess {
public :
bool operator() (const A& a1, const A& a2) const {
return a1.val < a2.val;
}
};

typedef set<A, ALess ASet;
typedef ASet::iterator ASetIter;
typedef std::pair<ASetIter, bool ASetInsRetVal;

int main() {
ASetInsRetVal retval;
ASet aset;

for(int i=0; i<4; i++) {
retval = aset.insert(D(i));
if(!retval.second)
cout << "insert failed\n";
else {
const D *dptr = static_cast<const D*>(&(*retval.first));
dptr->dfunc(); // crashes - see above
}
}
}
==============================================

解决方案

On 2008-07-02 21:13, Dom Jackson wrote:

I have a program which crashes when:

1 - I use static_cast to turn a base type pointer into a pointer to a
derived type

2 - I use this new pointer to call a function in an object of the
derived type

3 - this function then ''grows'' the derived type object (by pushing
onto a vector).

Is this actually possible, or should I be doing something else? In
more detail, what I''m doing is (there''s a complete test program below,
which crashes):

1 - I have a base class which doesn''t do very much;

2 - I declare a derived class with public inheritance from the base
class;

3 - the derived class has a method which pushes onto a vector in the
derived class;

4 - I create an STL set of base class objects;

5 - I then insert an object of the derived class into this set. I use
the set ''insert'' method, which returns an iterator to the new object
in the set, but this is an iterator to a *base* object (I hope)

6 - I convert the iterator to a pointer, and static_cast the pointer
to a pointer to an object of the derived class

7 - I call my new method via this pointer, pushing onto the vector in
the derived-class-object. Bang.

This will not work, std::set holds objects of the type given as a
parameter, in this case base-objects and not derived objects, the
derived objects will be sliced into base objects. So what you are doing
is trying to call a function which does not exist to manipulate a vector
that does not exist.

To solve your problem you could use a set of pointers to base instead of
a set of base (e.g. std::set<Base*instead of std::set<Base>) and
create the objects using new (e.g. set.insert(new Derived());).

Besides that, when casting from base to derived you should use
dynamic_cast and check if the cast succeeded (in which case the returned
pointer will be non-0). If you do that in your code you will notice that
you will always get a 0-pointer. A cast from pointer to base class to a
pointer to derived is only allowed if the object pointed to is of type
derived.

You can always cast from pointer to derived to pointer to base using
static_cast, but when going the other way you shall use dynamic_cast.

--
Erik Wikstr??m


On Jul 2, 4:31 pm, Erik Wikstr?m <Erik-wikst...@telia.comwrote:

You can always cast from pointer to derived to pointer to base using
static_cast, but when going the other way you shall use dynamic_cast.

"Shall" might be a bit strong here. There are cases where, because of
the
context, downcasting cannot fail. In this case, using dynamic cast
gives you
nothing except less performance.

You could however have a separate function that uses dynamic cast in
debug
but reverts to static cast in release, except for cases where the
dynamic cast
is actually part of the design (such as type switches, but these
should be
avoided when possible anyways).

--
Jonathan Mcdougall


Comments inline:
Dom Jackson <no****@mci2000.comwrote in
news:6q********************************@4ax.com:

I have a program which crashes when:

[snip.. the code is more interesting]

Any help much appreciated.

Thanks -

Dom

===========================================
#include <vector>
#include <set>
#include <iostream>

using std::vector;
using std::set;
using std::cout;

class A {
public:
A(int v) :
val(v) {}
int val;
};

class D : public A {
public:
D(int v) :
A(v) {}

mutable vector<intvec;

void dfunc(void) const {
std::cout << "hello world " << val << "!\n";
// ********************************************
// Ok without this line, crashes with this line
vec.push_back(val);
// ********************************************
}
};

class ALess {
public :
bool operator() (const A& a1, const A& a2) const {
return a1.val < a2.val;
}
};

typedef set<A, ALess ASet;
typedef ASet::iterator ASetIter;
typedef std::pair<ASetIter, bool ASetInsRetVal;

int main() {
ASetInsRetVal retval;
ASet aset;

for(int i=0; i<4; i++) {
retval = aset.insert(D(i));

This will slice your temporary D object into an A object. ASet contains
objects of type A, and only type A.

if(!retval.second)
cout << "insert failed\n";
else {
const D *dptr = static_cast<const D*>(&(*retval.first));

Undefined behaviour. retval->first is an A object. Which you then
force the compiler to try to treat it like a D object...

dptr->dfunc(); // crashes - see above

.... particularly when you attempt to access members which only exist in
D objects.

}
}
}
==============================================



这篇关于基类型静态向下转换为派生类型的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆