473,698 Members | 2,361 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

[Q] Strange dynamic_cast problem

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:

http://ericgorr.net/LibraryLoading.zip

which demonstrates the problem.

In Shared.h, there are the definitions of two purely virtual classes -
A & B. B is a subclass of A.

In LibraryA, there is a implementation of class B called BImp. There
is a function called GetA which returns a pointer to an instance of
BImp and returns an A*.

In LibraryB, there is a function called test. This function takes a
void *, which will end up being a function pointer to the GetA
function from LibraryA.

The problem comes in the test function with the line:

B* myB = dynamic_cast<B* (myA);

The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B.

However, I can make this dynamic_cast succeed, if in main.cp, which is
a part of the Application target, I set:

#define CASE_A 1

which allows

A *myA = functionPtr();
B *myB = dynamic_cast<B* (myA);

to be executed before the test function from LibraryB is called.

Any idea why this allows it to work?
Any idea why it is failing in the first place?

In main.cp, there are two #define's.

#define CASE_A 0
#define CASE_B 0

If both are set to zero, it will crash. This is simplest crashing
case.
If CASE_A is 1, it will work. Any idea why?
If CASE_B is 1, it will crash and this is the case closest to the real
case I am working with.

Since I started composing this message, I've been looking into the
issue a bit more and thought that if it were possible to make the
destructors pure virtual functions as well, then that would solve the
problem.

Googling for "pure virtual destructors c++", I came across:

http://www.linuxtopia.org/online_boo...ter15_024.html

While it seems strange, apparently this is allowed in C++.

So, if I changed Shared.h to look like:

*****
*****
#define VISIBLE __attribute__ ((visibility("d efault")))

class VISIBLE A
{
public:
virtual ~A( void ) = 0;
virtual void Func( void ) = 0;
};
A::~A() {}
class VISIBLE B : public A
{
public:
virtual ~B( void ) = 0;
virtual void Func1( void ) = 0;
};
B::~B() {}
extern "C" VISIBLE A *GetA( void );
*****
*****

everything worked in all three cases.

Any comments on this solution? Any reason why this wouldn't be
perfectly valid?

Any thoughts or comments would be appreciated.

Nov 4 '08
18 5281
On Nov 4, 5:01*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 3:40*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 2:40*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 11:58*am, Eric <ericg...@gmail .comwrote:
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:
*http://ericgorr.net/LibraryLoading.zip
which demonstrates the problem.
In Shared.h, there are the definitions of two purely virtual classes -
A & B. B is a subclass of A.
In LibraryA, there is a implementation of class B called BImp. There
is a function called GetA which returns a pointer to an instance of
BImp and returns an A*.
In LibraryB, there is a function called test. This function takes a
void *, which will end up being a function pointer to the GetA
function from LibraryA.
The problem comes in the test function with the line:
* * * * B* myB = dynamic_cast<B* (myA);
The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B.
prove it:
#include <iostream>
#include <typeinfo>
...
// should print a mangled representation of class B
std::cout << typeid(myA).nam e() << std::endl;
The getMyA function only has a single line of code:
* return new BImp;
and BImp is subclass of B which is a subclass of A.
Of course, typeid(myA).nam e() does not print a mangled representation
of class B (it prints 'P1A'), but this is the problem I am trying to
solve.
I don't know why (for certain) this does not work. Looking at the code
alone and stepping through it with the debugger, it is trivial to see
that it should be working. But when the dynamic_cast it hit, it fails.
I am beginning to think this is an OS specific issue as I mentioned in
a reply to sean.
A dynamic_cast will fail if:
b) the compiler is not configured to store RTTI (Real Time Type
Information)
I say your problem is b), but thats a
dice roll.
RTTI is configured properly.

Ah, so...

1) you are manually allocating and deallocating with new/delete so
virtual destructors are required in your base class. Not doing so
equates to a memory leak unless you use certain smart_pointers.

2) You stated:

[ The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B. ]

therefore myA is a pointer to an instance of B, should be

typeid( *myA ).name();

and you should be getting a B then.
Indeed I do. the output is: 4BImp

So, it does seem like the type is known and yet the dynamic_cast

B* myB = dynamic_cast<B* (myA);

is failing.

Nov 4 '08 #11
On Nov 4, 5:01*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 3:40*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 2:40*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 11:58*am, Eric <ericg...@gmail .comwrote:
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:
*http://ericgorr.net/LibraryLoading.zip
which demonstrates the problem.
In Shared.h, there are the definitions of two purely virtual classes -
A & B. B is a subclass of A.
In LibraryA, there is a implementation of class B called BImp. There
is a function called GetA which returns a pointer to an instance of
BImp and returns an A*.
In LibraryB, there is a function called test. This function takes a
void *, which will end up being a function pointer to the GetA
function from LibraryA.
The problem comes in the test function with the line:
* * * * B* myB = dynamic_cast<B* (myA);
The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B.
prove it:
#include <iostream>
#include <typeinfo>
...
// should print a mangled representation of class B
std::cout << typeid(myA).nam e() << std::endl;
The getMyA function only has a single line of code:
* return new BImp;
and BImp is subclass of B which is a subclass of A.
Of course, typeid(myA).nam e() does not print a mangled representation
of class B (it prints 'P1A'), but this is the problem I am trying to
solve.
I don't know why (for certain) this does not work. Looking at the code
alone and stepping through it with the debugger, it is trivial to see
that it should be working. But when the dynamic_cast it hit, it fails.
I am beginning to think this is an OS specific issue as I mentioned in
a reply to sean.
A dynamic_cast will fail if:
b) the compiler is not configured to store RTTI (Real Time Type
Information)
I say your problem is b), but thats a
dice roll.
RTTI is configured properly.

Ah, so...

1) you are manually allocating and deallocating with new/delete so
virtual destructors are required in your base class. Not doing so
equates to a memory leak unless you use certain smart_pointers.

2) You stated:

[ The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B. ]

therefore myA is a pointer to an instance of B, should be

typeid( *myA ).name();

and you should be getting a B then.
Indeed, I do. The output is: 4BImp. So, it would appear the type is
properly known.

And yet, the dynamic_cast is failing.

Nov 4 '08 #12
On Nov 4, 8:40 pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 11:58 am, Eric <ericg...@gmail .comwrote:
[...]
// should print a mangled representation of class B
std::cout << typeid(myA).nam e() << std::endl;
The standard doesn't say what it should print. And from a QoI
point of view, printing the mangled name rates at about the
bottom, just above always returning an empty string. A good
compiler will print the unmangled name.

--
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
Nov 5 '08 #13
On Nov 4, 10:46 pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 4:42 pm, Noah Roberts <u...@example.n etwrote:
[...]
The only use of a void* in the sample code is to pass around a
pointer to a function.
Which causes another problem: you can't store a pointer to a
function in a void*.

--
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
Nov 5 '08 #14
First of all, your code is not ready to be properly built. You need to
add #ifndef/#define/#endif include guards to your .h files. Second,
there is no main module which calls your test() function, so I don't
know how do you actually call it from your code. I also needed to add
declarations to your mainA.h and mainB.h files so I could use the
functions in my main module, and change the VISIBLE definition to an
empty one (my compiler doesn't support __attribute__). Anyway, using
Visual Studio 2008, I wrote this simple test program:

// main.cpp

#include "Shared.h"
#include "mainA.h"
#include "mainB.h"

int main()
{
test( &GetA );
return 0;
}

and it worked fine. BTW you are using an illegal C++ construct, that
is casting a function pointer to a void*. Your test() function should
probably look like this:

extern "C" VISIBLE void test( T* p );
Nov 5 '08 #15
On Nov 4, 3:17*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 5:01*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 3:40*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 2:40*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 11:58*am, Eric <ericg...@gmail .comwrote:
Ok...this seems to be treading into some really esoteric areas ofc++.
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 downto
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:
*http://ericgorr.net/LibraryLoading.zip
which demonstrates the problem.
In Shared.h, there are the definitions of two purely virtual classes -
A & B. B is a subclass of A.
In LibraryA, there is a implementation of class B called BImp. There
is a function called GetA which returns a pointer to an instance of
BImp and returns an A*.
In LibraryB, there is a function called test. This function takesa
void *, which will end up being a function pointer to the GetA
function from LibraryA.
The problem comes in the test function with the line:
* * * * B* myB = dynamic_cast<B* (myA);
The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B.
prove it:
#include <iostream>
#include <typeinfo>
...
// should print a mangled representation of class B
std::cout << typeid(myA).nam e() << std::endl;
The getMyA function only has a single line of code:
* return new BImp;
and BImp is subclass of B which is a subclass of A.
Of course, typeid(myA).nam e() does not print a mangled representation
of class B (it prints 'P1A'), but this is the problem I am trying to
solve.
I don't know why (for certain) this does not work. Looking at the code
alone and stepping through it with the debugger, it is trivial to see
that it should be working. But when the dynamic_cast it hit, it fails..
I am beginning to think this is an OS specific issue as I mentioned in
a reply to sean.
A dynamic_cast will fail if:
b) the compiler is not configured to store RTTI (Real Time Type
Information)
I say your problem is b), but thats a
dice roll.
RTTI is configured properly.
Ah, so...
1) you are manually allocating and deallocating with new/delete so
virtual destructors are required in your base class. Not doing so
equates to a memory leak unless you use certain smart_pointers.
2) You stated:
[ The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B. ]
therefore myA is a pointer to an instance of B, should be
typeid( *myA ).name();
and you should be getting a B then.

Indeed, I do. The output is: 4BImp. So, it would appear the type is
properly known.

And yet, the dynamic_cast is failing.
The problem is most likely that you end up with two definitions of the
type, one in each dynamic library (or one in main and one in the
library). The runtime system can't figure out that the two types are
are the same type, since they have separate v-tables and all that and
so fails to cast. The typical solution is to make sure that at least
one method from the base class is defined in only one dynamic library
(so define the constructor and virtual destructor in a .cpp rather
than the .h).

I am not sure if this is just a g++ issue or a general C++ issue.
Nov 5 '08 #16
On Nov 5, 8:12*am, Kamil Grabowski <grabowski.ka.. .@gmail.comwrot e:
First of all, your code is not ready to be properly built.
It builds and runs without error in Xcode 3.1.1 if CASE_A = 1.
>You need to
add #ifndef/#define/#endif include guards to your .h files.
Normally, I would agree, but such extra stuff isn't necessary in this
test case. If you found it to be necessary, you aren't building it
correctly.
Second,
there is no main module which calls your test() function, so I don't
know how do you actually call it from your code.
The main for the application is found in main.cp.

The application pulls the test function from LibraryB and then passes
it to LibraryA. It is inside of LibraryA that the test function is
called.
I also needed to add
declarations to your mainA.h and mainB.h files so I could use the
functions in my main module, and change the VISIBLE definition to an
empty one (my compiler doesn't support __attribute__).

and it worked fine.
I agree, this would work fine, but it has little to do with the
problem I am attempting to solve.

Nov 5 '08 #17
On Nov 5, 10:07*am, Daniel <drus...@gmail. comwrote:
On Nov 4, 3:17*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 5:01*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 3:40*pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 2:40*pm, Salt_Peter <pj_h...@yahoo. comwrote:
On Nov 4, 11:58*am, Eric <ericg...@gmail .comwrote:
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:
*http://ericgorr.net/LibraryLoading.zip
which demonstrates the problem.
In Shared.h, there are the definitions of two purely virtual classes -
A & B. B is a subclass of A.
In LibraryA, there is a implementation of class B called BImp. There
is a function called GetA which returns a pointer to an instance of
BImp and returns an A*.
In LibraryB, there is a function called test. This function takes a
void *, which will end up being a function pointer to the GetA
function from LibraryA.
The problem comes in the test function with the line:
* * * * B* myB = dynamic_cast<B* (myA);
The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B.
prove it:
#include <iostream>
#include <typeinfo>
...
// should print a mangled representation of class B
std::cout << typeid(myA).nam e() << std::endl;
The getMyA function only has a single line of code:
* return new BImp;
and BImp is subclass of B which is a subclass of A.
Of course, typeid(myA).nam e() does not print a mangled representation
of class B (it prints 'P1A'), but this is the problem I am trying to
solve.
I don't know why (for certain) this does not work. Looking at the code
alone and stepping through it with the debugger, it is trivial to see
that it should be working. But when the dynamic_cast it hit, it fails.
I am beginning to think this is an OS specific issue as I mentionedin
a reply to sean.
A dynamic_cast will fail if:
b) the compiler is not configured to store RTTI (Real Time Type
Information)
I say your problem is b), but thats a
dice roll.
RTTI is configured properly.
Ah, so...
1) you are manually allocating and deallocating with new/delete so
virtual destructors are required in your base class. Not doing so
equates to a memory leak unless you use certain smart_pointers.
2) You stated:
[ The dynamic_cast fails and myB is assigned NULL. This _should not_
fail because myA is an instance of class B. ]
therefore myA is a pointer to an instance of B, should be
typeid( *myA ).name();
and you should be getting a B then.
Indeed, I do. The output is: 4BImp. So, it would appear the type is
properly known.
And yet, the dynamic_cast is failing.

The problem is most likely that you end up with two definitions of the
type, one in each dynamic library (or one in main and one in the
library). The runtime system can't figure out that the two types are
are the same type, since they have separate v-tables and all that and
so fails to cast. The typical solution is to make sure that at least
one method from the base class is defined in only one dynamic library
(so define the constructor and virtual destructor in a .cpp rather
than the .h).
Yes, this is the conclusion I am reaching as well. The question is
what to do about it.

The underlying design being used here is for LibraryA to be a plugin
which provides the implementation for class B. LibraryB is another
plugin which needs to use the functionality provided by LibraryA. So,
Library B needs to know the information from Shared.h, but cannot know
*anything* about the implementation. I believe the problem is that the
destructor issue breaks the abstract purity of class A and class B,
providing some implementation and therefore duplicate definitions that
the dynamic_cast cannot figure out.

Maintaining this kind of separation does not seem possible with your
suggested solution and just using (mostly) straight C++.
I am not sure if this is just a g++ issue or a general C++ issue.
It appears to be OS & compiler specific as this all works when
compiled with Visual Studio.

I am coming to the conclusion issues such as these are why Apple
provided things like their CFPlugIn API. Because, as someone else has
pointed out,

-----
All the C++ specification specifies is what happens in a set of C++
source modules, all linked together to form one application. Nowhere
is it discussed what happens if you have DLL's, shared libraries, or
anything else with respect to the language.
-----


Nov 5 '08 #18
On Nov 5, 7:10*am, James Kanze <james.ka...@gm ail.comwrote:
On Nov 4, 10:46 pm, Eric <ericg...@gmail .comwrote:
On Nov 4, 4:42 pm, Noah Roberts <u...@example.n etwrote:

* *[...]
The only use of a void* in the sample code is to pass around a
pointer to a function.

Which causes another problem: you can't store a pointer to a
function in a void*.
Well, it works, but would be non-portable code.

However, this isn't the issue I am attempting to deal with at the
moment and in the real case, a void* isn't used. It was just done for
simplicity for this test case and is extremely unlikely to be the
cause of the problem.

Nov 5 '08 #19

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

Similar topics

13
4964
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 understand at compile time what is the right method to call. In the following example I tested the usage of...
8
2592
by: Thomas Lorenz | last post by:
Hello, first, I didn't find any reference to my question through googling. dynamic_cast uses RTTI to determine if the cast expression is valid. Invalid casts of pointers give a '0'-result. As it is the case in the following example: ----------------------------------------------------------- #include <iostream>
2
1753
by: yccheok | last post by:
Hello, I have an object called XXX previously derived from CDocument in my MDI project. Later, I create an concrete class called Subject. And I let XXX to have multiple inheritance from Subject (Subject is an object with protected constructor) The problem is, whenever I used dynamic_cast to cast a Subject pointer to XXX (I am quite sure Subject pointer is actually pointing to XXX), a visual c++ runtime error will occur.
5
2033
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 is derived from another pointer type. BTW: I cannot create a temporary instance, because used...
22
4802
by: Boris | last post by:
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<Level1*>(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...
5
3002
by: mijobee | last post by:
Hello Everyone, I just wanted to check that I'm using dynamic_cast correctly. I have a hierarchy of objects using pure virtual classes and virtual inheritance to implement interfaces. I ran into a problem using C-style casting to an instance of a derived class from its interface type to a variable of its concrete type. I was confused because I thought C-style casts always compiled even if they wouldn't run correctly at runtime. I...
15
2817
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;
15
12294
by: Bo Yang | last post by:
Hi, I can understand static_cast, reinterpret_cast and const_cast, they all work at compile time. But I can figure out how the C++'s dynamic- cast works? Could you please explain how for me? Thanks in advance! Regards! Bo
0
8674
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 usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9157
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...
0
9027
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 captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8895
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
8861
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
7725
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
3046
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
2
2329
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2001
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 effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.