473,289 Members | 1,829 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,289 software developers and data experts.

Problem with static downcast of base type to derived type

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
}
}
}
==============================================
Jul 2 '08 #1
10 3553
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
Jul 2 '08 #2
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
Jul 2 '08 #3
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.
}
}
}
==============================================

Jul 2 '08 #4
On Jul 2, 1:31*pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2008-07-02 21:13, Dom Jackson wrote:
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.
Of course the OP must have at least one virtual function in Base for
dynamic_cast to work.
A cast from pointer to base class to a
pointer to derived is only allowed if the object pointed to is of type
derived.
True.
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.
static_cast is fine even for downcasting, as long as the target type
is correct. static_cast is for when the destination type is known at
compile time.

Did you mean that static_cast can not be used in polymorphic
hierarchies? If so, it's news to me and I don't have the standard
handy to check. :)

Ali
Jul 2 '08 #5
Thanks folks - I had no idea that you couldn't put a derived type in a
set of base types. I can't immediately see anything in Josuttis about
this. Can anyone tell me what the problem is here? Is this common to
all STL containers? I had rather naively assumed that an object of a
derived type actually was, to all intents and purposes, also a base
object, but that's obviously not the case.

Thanks -

Dom
Jul 2 '08 #6
On Jul 2, 10:48 pm, Jonathan Mcdougall <jonathanmcdoug...@gmail.com>
wrote:
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.
It also gives you defined behavior in case you are mistaken.
You should use dynamic_cast until the profiler says otherwise,
even if you think you know that static_cast would be safe.
You could however have a separate function that uses dynamic
cast in debug but reverts to static cast in release,
You don't really mean to say that you deliver different code
than what you've tested, do you? Again, unless the profiler
says it's absolutely imperative, you deliver the same code,
compiled with the same options, as you use during development.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 3 '08 #7
On Jul 2, 11:06 pm, acehr...@gmail.com wrote:
On Jul 2, 1:31 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2008-07-02 21:13, Dom Jackson wrote:
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.
Of course the OP must have at least one virtual function in
Base for dynamic_cast to work.
Of course, if Base doesn't have at least one virtual function,
there's probably no point in deriving from it.
A cast from pointer to base class to a pointer to derived is
only allowed if the object pointed to is of type derived.
True.
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.
static_cast is fine even for downcasting, as long as the
target type is correct.
Which, of course, means that there is a distinct risk of an
error, resulting in undefined behavior. The choice is basically
whether you want undefined behavior or defined behavior in case
of an error.
static_cast is for when the destination type is known at
compile time.
Static_cast is for many things, but in the case of Base* to
Derived*, it should only be used when the profiler says you have
no other choice. (Practically, of course, there should be very,
very few Base* to Derived* conversions to begin with.)
Did you mean that static_cast can not be used in polymorphic
hierarchies? If so, it's news to me and I don't have the
standard handy to check. :)
It can only be used in limited ways: you can't convert from a
virtual base to a derived (pointer or reference), for example,
and you can't arbitrarily navigate in the hierarchy.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 3 '08 #8
On Jul 2, 11:29 pm, Dom Jackson <nos...@mci2000.comwrote:
Thanks folks - I had no idea that you couldn't put a derived
type in a set of base types. I can't immediately see anything
in Josuttis about this.
What should he say? He certainly says that the containers
contain objects of type T. In C++, an object of type T is an
object of type T, and not an object of some other type.
Polymorphism only works through references and pointers.
Can anyone tell me what the problem is here?
There is no problem. In C++, containers contain objects, with
value semantics.
Is this common to all STL containers? I had rather naively
assumed that an object of a derived type actually was, to all
intents and purposes, also a base object, but that's obviously
not the case.
It's never the case. An object of a derived type is an object
of a derived type, and an object of a base type is an object of
a base type. Every object has one, and only one type. This is
a fundamental aspect of the C++ object model (and also the
object model of many other languages).

Written correctly, an object of a derived type can be used as an
object of a base type, but only if the "use" involves an
indirection (reference or pointer). The object still has a
specific type, which never changes (but a pointer or a
reference can designate different objects).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 3 '08 #9
On Jul 2, 1:31*pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2008-07-02 21:13, Dom Jackson wrote:
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());).

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.
No, a dynamic_cast<cannot be used in the original program to cast
from an A to a B pointer - because the A class is not a polymorphic
type.

Greg
Jul 3 '08 #10
Thanks everyone - I re-implemented my set as a collection of pointers
and it's all working now.

Dom
Jul 3 '08 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Omer van Kloeten | last post by:
The Top Level Design: The class Base is a factory class with a twist. It uses the Assembly/Type classes to extract all types that inherit from it and add them to the list of types that inherit...
12
by: cppaddict | last post by:
Hi, I know that it is illegal in C++ to have a static pure virtual method, but it seems something like this would be useful when the following 2 conditions hold: 1. You know that every one...
4
by: Gopal-M | last post by:
I have the problem with sizeof operator I also want to implement a function that can return size of an object. My problem is as follows.. I have a Base class, say Base and there are many class...
4
by: Bangalore | last post by:
Hi all, I am finding quite difficulty in understanding the behaviour of the following program. Base class is singleton, so it should allow the creation of only one object. Eventhough it is...
8
by: | last post by:
#include <iostream> using namespace std; class Base { public: Base() {} ~Base() {} };
12
by: Hemanth | last post by:
Hi, I have a base class with a static constructor and some abstract methods. Derived classes implement these methods. From articles on the web, it appears that there is no guarentee that this...
14
by: Dave Booker | last post by:
It looks like the language is trying to prevent me from doing this sort of thing. Nevertheless, the following compiles, and I'd like to know why it doesn't work the way it should: public class...
8
by: crjjrc | last post by:
Hi, I've got a base class and some derived classes that look something like this: class Base { public: int getType() { return type; } private: static const int type = 0; };
2
by: cmonthenet | last post by:
Hello, I searched for an answer to my question and found similar posts, but none that quite addressed the issue I am trying to resolve. Essentially, it seems like I need something like a virtual...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: marcoviolo | last post by:
Dear all, I would like to implement on my worksheet an vlookup dynamic , that consider a change of pivot excel via win32com, from an external excel (without open it) and save the new file into a...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.