473,761 Members | 8,011 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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(v al);
// *************** *************** **************
}
};

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<ASetI ter, bool ASetInsRetVal;

int main() {
ASetInsRetVal retval;
ASet aset;

for(int i=0; i<4; i++) {
retval = aset.insert(D(i ));
if(!retval.seco nd)
cout << "insert failed\n";
else {
const D *dptr = static_cast<con st D*>(&(*retval.f irst));
dptr->dfunc(); // crashes - see above
}
}
}
=============== =============== =============== =
Jul 2 '08 #1
10 3599
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*i nstead 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.c om:
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(v al);
// *************** *************** **************
}
};

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<ASetI ter, 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.seco nd)
cout << "insert failed\n";
else {
const D *dptr = static_cast<con st D*>(&(*retval.f irst));
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 objektorientier ter Datenverarbeitu ng
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 objektorientier ter Datenverarbeitu ng
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 objektorientier ter Datenverarbeitu ng
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*i nstead 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<ca nnot 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

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

Similar topics

3
3151
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 from it. During run time, using a static method, the class creates an instance of the derived class using the Activator class and returns it. This design pattern is very similar to the design pattern applied by the Assembly class. The twist is...
12
13467
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 of your Derived classes will need to implement some method, but implement it differently, and that the base class cannot implement it. This is where pure virtual comes in.
4
3107
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 derived from it. At a particular point in my application I need the size of the object pointed to by the base pointer. Eg
4
1403
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 singleton , i tried to create three objects from it, and I succeeded with only one object with address "0x1003b010"
8
12662
by: | last post by:
#include <iostream> using namespace std; class Base { public: Base() {} ~Base() {} };
12
3442
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 static constructor of the base class would be invoked even if a an object of the derived class is created. Is this correct ? Is there any way to ensure the base class's static constructor is invoked before the derived class instance is constructed ?...
14
33286
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 ComponentA { static string s_name = "I am the root class."; public string Name { get {return s_name;} } }
8
2888
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
2412
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 static function (which I know is illegal), but, is there a way to provide something similar? The class that is the target of my inquiry is a template class that interfaces to one of several derived classes through a pointer to a base class. The...
0
9376
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10136
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9923
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9811
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8813
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7358
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6640
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5405
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3911
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

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.