473,545 Members | 1,558 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

dynamic_cast from base to another parent of derived class

I'm porting code from Windows to UNIX and ran into a problem with
dynamic_cast. Imagine a class hierarchy with three levels: class Level2
derives from Level1 which derives from Base. If you look now at this code:

Base *b = new Level2();
Level1 *l1 = dynamic_cast<Le vel1*>(b);

Should dynamic_cast return a valid pointer or 0? I wonder as Visual Studio
2005 returns a valid pointer while g++ 3.4.6 returns 0. Both compilers work
as expected when dynamic_cast<Le vel2*is used but return different results
with the code above. Who is right?

The class hierarchy I'm talking about has some more classes per level.
That's why sometimes a dynamic_cast to a level 1 class is preferred as you
can then operate on various level 2 classes which are all derived from the
same level 1 class. If you have to downcast to the actual level 2 class you
end up writing the same code for several level 2 classes which I would like
to avoid.

Boris
Oct 3 '06 #1
22 4785
Boris wrote:
I'm porting code from Windows to UNIX and ran into a problem with
dynamic_cast. Imagine a class hierarchy with three levels: class Level2
derives from Level1 which derives from Base. If you look now at this code:

Base *b = new Level2();
Level1 *l1 = dynamic_cast<Le vel1*>(b);

Should dynamic_cast return a valid pointer or 0? I wonder as Visual Studio
2005 returns a valid pointer while g++ 3.4.6 returns 0. Both compilers work
as expected when dynamic_cast<Le vel2*is used but return different results
with the code above. Who is right?
If Base has at least one virtual function (a prerequisite for applying
dynamic_cast to a Base*) and that the various bases are public,
dynamic_cast<Le vel1*>(b) does just what you would expect: it returns a
pointer to the Level1 subobject in the original Level2 object.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Oct 3 '06 #2
Pete Becker wrote:
Boris wrote:
>I'm porting code from Windows to UNIX and ran into a problem with
dynamic_cast . Imagine a class hierarchy with three levels: class
Level2 derives from Level1 which derives from Base. If you look now
at this code: Base *b = new Level2();
Level1 *l1 = dynamic_cast<Le vel1*>(b);

Should dynamic_cast return a valid pointer or 0? I wonder as Visual
Studio 2005 returns a valid pointer while g++ 3.4.6 returns 0. Both
compilers work as expected when dynamic_cast<Le vel2*is used but
return different results with the code above. Who is right?

If Base has at least one virtual function (a prerequisite for applying
dynamic_cast to a Base*) and that the various bases are public,
dynamic_cast<Le vel1*>(b) does just what you would expect: it returns a
pointer to the Level1 subobject in the original Level2 object.
Thanks for your reply, Pete! When I create a small test program which works
with the original class hierarchy there is no problem with dynamic_cast.

The code I talk about looks like this:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}

There is an explicit check (b is a reference to an instance of Base here)
before dynamic_cast is used. The requirements you mentioned above are also
met (Base has virtual functions and public inheritance is used everwhere).
The compiler doesn't complain either when it sees this code. When I
dynamic_cast to level2* I get a valid pointer, too. I play around some more
to figure out what's going on. If you or anyone else has an idea what might
affect dynamic_cast I would be happy to hear it!

Boris
Oct 3 '06 #3
Boris wrote:
Pete Becker wrote:
Boris wrote:
I'm porting code from Windows to UNIX and ran into a problem with
dynamic_cast. Imagine a class hierarchy with three levels: class
Level2 derives from Level1 which derives from Base. If you look now
at this code: Base *b = new Level2();
Level1 *l1 = dynamic_cast<Le vel1*>(b);

Should dynamic_cast return a valid pointer or 0? I wonder as Visual
Studio 2005 returns a valid pointer while g++ 3.4.6 returns 0. Both
compilers work as expected when dynamic_cast<Le vel2*is used but
return different results with the code above. Who is right?
If Base has at least one virtual function (a prerequisite for applying
dynamic_cast to a Base*) and that the various bases are public,
dynamic_cast<Le vel1*>(b) does just what you would expect: it returns a
pointer to the Level1 subobject in the original Level2 object.

Thanks for your reply, Pete! When I create a small test program which works
with the original class hierarchy there is no problem with dynamic_cast.

The code I talk about looks like this:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}

There is an explicit check (b is a reference to an instance of Base here)
before dynamic_cast is used. The requirements you mentioned above are also
met (Base has virtual functions and public inheritance is used everwhere).
The compiler doesn't complain either when it sees this code. When I
dynamic_cast to level2* I get a valid pointer, too. I play around some more
to figure out what's going on. If you or anyone else has an idea what might
affect dynamic_cast I would be happy to hear it!

Boris
One syntactic simplification:

if ( const level1 *const l1 = dynamic_cast<co nst level1*>(&b) )
{
// Use l1 here
}
else
{
// l1 is null here
}

Cheers! --M

Oct 3 '06 #4
Boris wrote:
[...] The code I talk about looks like this:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}
I changed the code for testing purposes and replaced dynamic_cast with
reinterpret_cas t - this works.

I changed then the code to make it look like this:

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}

This works, too. Is there any other possible explanation than a compiler bug
why a dynamic_cast<co nst level1*should not work?

Boris
Oct 3 '06 #5
[crossposted to gnu.g++.help]

Boris wrote:
Boris wrote:
>[...] The code I talk about looks like this:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}

I changed the code for testing purposes and replaced dynamic_cast with
reinterpret_cas t - this works.

I changed then the code to make it look like this:

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}

This works, too. Is there any other possible explanation than a
compiler bug why a dynamic_cast<co nst level1*should not work?
It looks like a problem with g++. The code I was talking about is in a
shared library. When I link the executable statically dynamic_cast works.
When I use however the shared library dynamic_cast returns 0. Same code but
different behavior due to linking.

There is a section "dynamic_ca st, throw, typeid don't work with shared
libraries" at http://gcc.gnu.org/faq.html#dso. From what I understand though
there is not much you can do? I'm using version 3.4.6 of g++ which is the
latest of the 3.4.x series.

The code construct as above with dynamic_cast is used in various project
files. When building and linking the shared library some work, others don't.
I don't know though on what it depends why some dynamic_casts don't work and
falsely return 0. Is there anything I can do except replacing all
dynamic_casts? Any g++ experts with ideas?

Boris
Oct 3 '06 #6

Boris wrote:
[crossposted to gnu.g++.help]

Boris wrote:
Boris wrote:
[...] The code I talk about looks like this:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}
I changed the code for testing purposes and replaced dynamic_cast with
reinterpret_cas t - this works.

I changed then the code to make it look like this:

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}

This works, too. Is there any other possible explanation than a
compiler bug why a dynamic_cast<co nst level1*should not work?
Why not just:

if(level2 const* l2 = dynamic_cast<le vel2 const*>(&b))
{
// no need comparing typeinfo's
}

?
>
It looks like a problem with g++. The code I was talking about is in a
shared library. When I link the executable statically dynamic_cast works.
When I use however the shared library dynamic_cast returns 0. Same code but
different behavior due to linking.

There is a section "dynamic_ca st, throw, typeid don't work with shared
libraries" at http://gcc.gnu.org/faq.html#dso.
I wonder how you reached such a conclusion. Where on that page do they
say it does not work?

Oct 4 '06 #7
Maxim Yegorushkin wrote:
[...]

Why not just:

if(level2 const* l2 = dynamic_cast<le vel2 const*>(&b))
{
// no need comparing typeinfo's
}

?
I want to cast to a level 1 class which is a parent of several level 2
classes. Otherwise you are right - I could cast to the actual type directly.
The real code looks more like this:

if (typeid(b) == typeid(level2a) || typeid(b) == typeid(level2b) ||
typeid(b) == typeid(level2c) )
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}

Class level1 is the parent of all the level2 classes. I have to check for
several types but don't need to write the same code then at least for all
the level2 classes.
>It looks like a problem with g++. The code I was talking about is in
a shared library. When I link the executable statically dynamic_cast
works. When I use however the shared library dynamic_cast returns 0.
Same code but different behavior due to linking.

There is a section "dynamic_ca st, throw, typeid don't work with
shared libraries" at http://gcc.gnu.org/faq.html#dso.

I wonder how you reached such a conclusion. Where on that page do they
say it does not work?
The title is pretty clear I think: "dynamic_cast,t hrow, typeid don't work
with shared libraries". :-) They are talking about template instantiations,
vague linkage, not an exhaustive list, namesspaces etc. This all doesn't
sound like adding a linker switch fixes all your problems. This sounds like
be ready for all kind of problems.

Anyway if I can downcast to the actual type and then back to its parent with
the following code (no compilation error, no runtime error) why should a
dynamic_cast to the parent l1 not work?

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}

Boris
Oct 4 '06 #8
Boris wrote:
>I wonder how you reached such a conclusion. Where on that page do
they say it does not work?

The title is pretty clear I think: "dynamic_cast,t hrow, typeid don't
work with shared libraries". :-) They are talking about template
instantiations, vague linkage, not an exhaustive list, namesspaces
etc. This all doesn't sound like adding a linker switch fixes all
your problems. This sounds like be ready for all kind of problems.

Anyway if I can downcast to the actual type and then back to its
parent with the following code (no compilation error, no runtime
error) why should a dynamic_cast to the parent l1 not work?

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}
I changed the code to use boost::polymorp hic_downcast instead of
dynamic_cast:

if (typeid(b) == typeid(level2))
{
const level1 *l1 = boost::polymorp hic_downcast<co nst level1*>(&b);
}

With NDEBUG defined boost::polymorp hic_downcast uses only static_cast - this
works. Without NDEBUG defined dynamic_cast is used which doesn't work (as an
assert fails).

Summary: Everything works with reinterpret_cas t and static_cast or
dynamic_cast when statically linked. It fails when dynamic_cast is used in a
shared library. It can not be reproduced with a small test case as
everything works then. The project I port to UNIX uses dynamic_casts in
different files where some do work. There must be some more conditions which
make g++ produce wrong code and which make some dynamic_casts fail
constantly.

Boris
Oct 4 '06 #9

Boris wrote:
Maxim Yegorushkin wrote:
[...]

Why not just:

if(level2 const* l2 = dynamic_cast<le vel2 const*>(&b))
{
// no need comparing typeinfo's
}

?

I want to cast to a level 1 class which is a parent of several level 2
classes. Otherwise you are right - I could cast to the actual type directly.
The real code looks more like this:

if (typeid(b) == typeid(level2a) || typeid(b) == typeid(level2b) ||
typeid(b) == typeid(level2c) )
{
const level1 *l1 = dynamic_cast<co nst level1*>(&b);
}

Class level1 is the parent of all the level2 classes. I have to check for
several types but don't need to write the same code then at least for all
the level2 classes.
I would redesign my hierarchy so, that dynamic_cast would be enough.
It looks like a problem with g++. The code I was talking about is in
a shared library. When I link the executable statically dynamic_cast
works. When I use however the shared library dynamic_cast returns 0.
Same code but different behavior due to linking.

There is a section "dynamic_ca st, throw, typeid don't work with
shared libraries" at http://gcc.gnu.org/faq.html#dso.
I wonder how you reached such a conclusion. Where on that page do they
say it does not work?

The title is pretty clear I think: "dynamic_cast,t hrow, typeid don't work
with shared libraries". :-) They are talking about template instantiations,
vague linkage, not an exhaustive list, namesspaces etc. This all doesn't
sound like adding a linker switch fixes all your problems. This sounds like
be ready for all kind of problems.
This is a title of a frequently asked question. The answer is given fow
to make it work. If you can follow the first advise, which is

<q>
For a program which is linked against a shared library, no additional
precautions are needed
</q>

then no other action is required.
Anyway if I can downcast to the actual type and then back to its parent with
the following code (no compilation error, no runtime error) why should a
dynamic_cast to the parent l1 not work?

if (typeid(b) == typeid(level2))
{
const level2 *l2 = dynamic_cast<co nst level2*>(&b);
const level1 *l1 = l2;
}
You could find more help if you posted simplified complete code that
reproduces what you are observing.

It might be that you derive privately from your base (class A : B {};)
.. dynamic_cast in this case does not work, reinterpret_cas t does work
if your base class is first in the list of the base classes.

Oct 4 '06 #10

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

Similar topics

18
2805
by: Andreas Sch. | last post by:
Hello, I had been quite suprised by the following little program: ---- cut ---- #include "iostream.h" class base {
13
4944
by: GianGuz | last post by:
Everyone knows about the complex and cpu-expensive procedures taken by dynamic_cast to find the right function call in a virtual classes hierarchy. The question I would to rise is when dynamic_cast is really necessary? A wise usage of templates and/or non dynamic_cast operators can grant the compiler with any information it needs to...
5
2028
by: tthunder | last post by:
Hi @all, Perhaps some of you know my problem, but I had to start a new thread. The old one started to become very very confusing. Here clean code (which compiles well with my BCB 6.0 compiler). You can find a problem there, which cannot be solved by dynamic_cast, because the pointers can be NULL, and I only want to know, if the pointer type...
15
2807
by: Grizlyk | last post by:
Hello. Returning to question of manual class type identification, tell me, for ordinary inheritance is C++ garantee that dynamic_cast<Derived*>(Base*) can be implemented similarly to return (Base*->type_fild >= Derived_typeid)? Base*: 0;
8
5422
by: pietromas | last post by:
In the example below, why does the dynamic_cast fail (return NULL)? It should be able to cast between sibling classes ... #include <iostream> class A { public: virtual const int get() const = 0;
13
2108
by: baltasarq | last post by:
Hi, there ! When I use dynamic_cast for a single object, I do something like: void foo(Base *base) { if ( dynamic_cast<Derived *>( base ) != NULL ) { ((Derived *) base)->do_something() } }
6
1889
by: Generic Usenet Account | last post by:
I ran a small experiment involving RTTI and dynamic casting. Basically what I did was to cast a base class pointer to a derived type (yes, I know that is not kosher). I then performed dynamic_casting and I invoked RTTI. In both instances, the run time environment did not pick up the fact that what I was claiming to be a derived pointer was...
25
3108
by: lovecreatesbea... | last post by:
Suppose I have the following three classes, GrandBase <-- Base <-- Child <-- GrandChild The following cast expression holds true only if pBase points object of type of ``Child'' or ``GrandChild'', i.e. types not upper than Child in the above class hierarchy, dynamic_cast<Child*>pBase
18
5264
by: Eric | last post by:
Ok...this seems to be treading into some really esoteric areas of c++. I will do my best to explain this issue, but I don't fully understand what is happening myself. I am hoping that the problem comes down to standard c++ stuff and is not specific to Mac OS X compiler&linker. I have put together a simple test project which can be found at:...
0
7467
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7656
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. ...
0
7807
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7419
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...
1
5326
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...
0
4944
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...
0
3450
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3442
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
703
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

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.