dynamic_cast doesn't return the correct values: e.g. in my project I have a
lot of classes, say A, B, C, D - D being the most derived, A being base - if
I put printf(this) in the constructors of them they all get different
values, e.g.
A will be 0x12fec0,
B will be 0x12fec4,
C will be 0x12fec8,
D will be 0x12fecc, ..etc.

I thought this was supposed to happen, but if I have an A* called "pa"
(knowing myself that it is also a D*)
if I do
void test(A* pa)
{
D* pd = dynamic_cast<D*>(pa);
// then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!
}
I tried to build a test project to demonstrate but in that all the
constructors printed the same values! Help!
And yes I have got multiple inheritance, I have also got virtual
inheritance.

Re: dynamic_cast is shite! by Victor

Victor
Fri May 06 13:48:56 CDT 2005

Bonj wrote:
> dynamic_cast doesn't return the correct values: e.g. in my project I have a
> lot of classes, say A, B, C, D - D being the most derived, A being base - if
> I put printf(this) in the constructors of them they all get different
> values, e.g.
> A will be 0x12fec0,
> B will be 0x12fec4,
> C will be 0x12fec8,
> D will be 0x12fecc, ..etc.
>
> I thought this was supposed to happen, but if I have an A* called "pa"
> (knowing myself that it is also a D*)
> if I do
> void test(A* pa)
> {
> D* pd = dynamic_cast<D*>(pa);
> // then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!
> }
> I tried to build a test project to demonstrate but in that all the
> constructors printed the same values! Help!
> And yes I have got multiple inheritance, I have also got virtual
> inheritance.

dynamic_cast only works if the classes are polymorphic (have virtual
functions). Do your classes qualify?

V

Re: dynamic_cast is shite! by Michael

Michael
Fri May 06 15:48:16 CDT 2005


"Bonj" <a@b.com> wrote in message
news:edytZrmUFHA.3176@TK2MSFTNGP12.phx.gbl...

> ... printf(this) in the constructors of them they all get different
> values, e.g.
> A will be 0x12fec0,
> B will be 0x12fec4,
> C will be 0x12fec8,
> D will be 0x12fecc, ..etc.
>
...
> D* pd = dynamic_cast<D*>(pa);
> // then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!

dynamic_cast doesn't change the value of an object; it only changes the way
the compiler interprets it.



Re: dynamic_cast is shite! by Bonj

Bonj
Fri May 06 15:51:44 CDT 2005


> dynamic_cast only works if the classes are polymorphic (have virtual
> functions). Do your classes qualify?
>


Yep. They sure do. They all have at least a virtual destructor, the ones in
question also have a lot of other virtual functions.



Re: dynamic_cast is shite! by Bonj

Bonj
Fri May 06 16:53:54 CDT 2005

I think I've made a breakthrough, don't know about solved it but definitely
discovered something: it seems to be that I was making the following
mistake:
I was experiencing the problem described below of differing values of 'this'
when I had something like the following model
class IReg {};
class IWin : virtual public IReg {};
class IChildWin : virtual public IReg {};
class IODable : virtual public IReg {};
class WPWin : public IWin {};
class SplitWin : public WPWin, public IChildWin {};
class ODCombo : public IWin, public IChildWin, public IODable {}
class DPWin : public WPWin {}; //...etc

My logic was that since IReg is the only thing that's in danger of being
inherited twice from two different branches from the same base (e.g.
SplitWin gets one from WPWin through IWin, and another from IChildWin) then
IReg is the only thing that needs to be specified virtually inherited, hence
I just made it so that everything that directly derives from IReg virtually
inherits it, thinking that would make sure each class only has one 'copy' of
IReg. Not so! I got this from the microsoft documentation, but it seems I
understood it wrong...
IReg's default constructor was firing all over the place, when it shouldn't
have been.
I chopped and changed it around a bit, and I discovered that the correct
model is this:
class IReg {};
class IWin : public IReg {};
class IChildWin : public IReg {};
class IODable : public IReg {};
class WPWin : public IWin {};
class SplitWin : public WPWin, virtual public IChildWin {};
class ODCombo : public IWin, virtual public IChildWin, virtual public
IODable {}
class DPWin : public WPWin {}; //...etc

don't know whether that explains it?

"Victor Bazarov" <v.Abazarov@comAcast.net> wrote in message
news:uRfGDxmUFHA.1040@TK2MSFTNGP10.phx.gbl...
> Bonj wrote:
>> dynamic_cast doesn't return the correct values: e.g. in my project I have
>> a
>> lot of classes, say A, B, C, D - D being the most derived, A being base -
>> if
>> I put printf(this) in the constructors of them they all get different
>> values, e.g.
>> A will be 0x12fec0,
>> B will be 0x12fec4,
>> C will be 0x12fec8,
>> D will be 0x12fecc, ..etc.
>>
>> I thought this was supposed to happen, but if I have an A* called "pa"
>> (knowing myself that it is also a D*)
>> if I do
>> void test(A* pa)
>> {
>> D* pd = dynamic_cast<D*>(pa);
>> // then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!
>> }
>> I tried to build a test project to demonstrate but in that all the
>> constructors printed the same values! Help!
>> And yes I have got multiple inheritance, I have also got virtual
>> inheritance.
>
> dynamic_cast only works if the classes are polymorphic (have virtual
> functions). Do your classes qualify?
>
> V



Re: dynamic_cast is shite! by Carl

Carl
Fri May 06 23:15:09 CDT 2005

Bonj wrote:
> I think I've made a breakthrough, don't know about solved it but
> definitely discovered something: it seems to be that I was making the
> following mistake:
> I was experiencing the problem described below of differing values of
> 'this' when I had something like the following model
> class IReg {};
> class IWin : virtual public IReg {};
> class IChildWin : virtual public IReg {};
> class IODable : virtual public IReg {};
> class WPWin : public IWin {};
> class SplitWin : public WPWin, public IChildWin {};
> class ODCombo : public IWin, public IChildWin, public IODable {}
> class DPWin : public WPWin {}; //...etc
>
> My logic was that since IReg is the only thing that's in danger of
> being inherited twice from two different branches from the same base
> (e.g. SplitWin gets one from WPWin through IWin, and another from
> IChildWin) then IReg is the only thing that needs to be specified
> virtually inherited, hence I just made it so that everything that
> directly derives from IReg virtually inherits it, thinking that would
> make sure each class only has one 'copy' of IReg. Not so! I got this
> from the microsoft documentation, but it seems I understood it
> wrong...

You understood correctly, and from what you've posted, used virtual
inheritance correctly. What leads you to believe that it didn't work
correctly?

> IReg's default constructor was firing all over the place, when it
> shouldn't have been.
> I chopped and changed it around a bit, and I discovered that the
> correct model is this:
> class IReg {};
> class IWin : public IReg {};
> class IChildWin : public IReg {};
> class IODable : public IReg {};
> class WPWin : public IWin {};
> class SplitWin : public WPWin, virtual public IChildWin {};
> class ODCombo : public IWin, virtual public IChildWin, virtual public
> IODable {}
> class DPWin : public WPWin {}; //...etc

This topology does result in two IReg members in each instance of SplitWin
or ODCombo.

Note that if your IXxxxx classes are truly interface classes, it really
doesn't matter how many "copies" of that interface you inherit - each will
occupy zero or 1 bytes of space in your derived class. (The standard
permits something know as the empty base class optimization in which a base
class is not required to have any size at all. Multiple inheritance,
however, forces a conforming compiler to make some bases have a size to
avoid having two sub-objects with the same address. I don't recall where
VC++ falls in this regard, but I think empty base classes always have a size
of zero under VC++).

As far as the results of dynamic_cast and examining the 'this' pointer
values: You have to be very careful when second-guessing the compiler. In
particular, in the case of VC++, a base class may appear to have two or more
different values of 'this' depending on how and where you examine it. This
is due to 'this pointer adjustments' that are applied to ensure that a
member of C1 can always call another member of C1 without adjusting the
aparent value of the 'this' pointer.

I'd suggest you put the code back the way you had it originally, and if it
doesn't work, post a bit more detail about how you're determining that it
doesn't work - because in all likelihood, it's a coding error on your part.
Multiple and Virtual inheritance works - and so does dynamic_cast (modulo
that bug I mentioned with dynamic_cast from the constructor).

-cd



Re: dynamic_cast is shite! by Bonj

Bonj
Sat May 07 05:37:35 CDT 2005

I've decided that multiple inheritance is more trouble than it's worth, and
I've bunged all the code from IWPWindow and IChildWindow into IWindow,
making 'ISuperWindow'. The distinction between child windows and top-level
window(s) is easy - I have two create methods instead of one,
CreateFromClass(LPCTSTR class, DWORD style) and CreateWithWndProc(style) :-
CreateWithWndProc then just calls CreateFromClass(Initialize(), style),
where Initialize is protected and the only thing that calls RegisterClassEx.
The top-level windows then just don't bother overriding the On~()
notification handlers. That makes it a lot simpler, and it means that no
class needs to inherit from IChildWindow aswell as IWindow - they get all
the overloads in IWindow. I then have 3 layers of windows - the base class
IWindow itself, different types of windows (e.g. generic TreeView window,
MDIClientWindow) and then the third layer that is in the .exe project itself
are the app-specific windows.
This is causing some problems - one of the second-layer windows is having an
exception violation reading 0xccccccd0 in its constructor straight after its
base and member initializer lists have fired, I don't know what's causing
this at the moment but hopefully it'll be elementary because I have done
away with all the base initializer lists entirely as they were getting
cumbersome....

I read the bit about with single inheritance, all the 'this' pointers can
be relied upon to have the same value, this is what I need really when I'm
relying on them being the specific pointers they're claiming to be. I can
even use my own bitset-based RTTI purely for optimization's sake, knowing
that I can safely whack in a reinterpret for good measure and general
hardcore-ness.


"Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
wrote in message news:%23sYEetrUFHA.3840@tk2msftngp13.phx.gbl...
> Bonj wrote:
>> I think I've made a breakthrough, don't know about solved it but
>> definitely discovered something: it seems to be that I was making the
>> following mistake:
>> I was experiencing the problem described below of differing values of
>> 'this' when I had something like the following model
>> class IReg {};
>> class IWin : virtual public IReg {};
>> class IChildWin : virtual public IReg {};
>> class IODable : virtual public IReg {};
>> class WPWin : public IWin {};
>> class SplitWin : public WPWin, public IChildWin {};
>> class ODCombo : public IWin, public IChildWin, public IODable {}
>> class DPWin : public WPWin {}; //...etc
>>
>> My logic was that since IReg is the only thing that's in danger of
>> being inherited twice from two different branches from the same base
>> (e.g. SplitWin gets one from WPWin through IWin, and another from
>> IChildWin) then IReg is the only thing that needs to be specified
>> virtually inherited, hence I just made it so that everything that
>> directly derives from IReg virtually inherits it, thinking that would
>> make sure each class only has one 'copy' of IReg. Not so! I got this
>> from the microsoft documentation, but it seems I understood it
>> wrong...
>
> You understood correctly, and from what you've posted, used virtual
> inheritance correctly. What leads you to believe that it didn't work
> correctly?
>
>> IReg's default constructor was firing all over the place, when it
>> shouldn't have been.
>> I chopped and changed it around a bit, and I discovered that the
>> correct model is this:
>> class IReg {};
>> class IWin : public IReg {};
>> class IChildWin : public IReg {};
>> class IODable : public IReg {};
>> class WPWin : public IWin {};
>> class SplitWin : public WPWin, virtual public IChildWin {};
>> class ODCombo : public IWin, virtual public IChildWin, virtual public
>> IODable {}
>> class DPWin : public WPWin {}; //...etc
>
> This topology does result in two IReg members in each instance of SplitWin
> or ODCombo.
>
> Note that if your IXxxxx classes are truly interface classes, it really
> doesn't matter how many "copies" of that interface you inherit - each will
> occupy zero or 1 bytes of space in your derived class. (The standard
> permits something know as the empty base class optimization in which a
> base class is not required to have any size at all. Multiple inheritance,
> however, forces a conforming compiler to make some bases have a size to
> avoid having two sub-objects with the same address. I don't recall where
> VC++ falls in this regard, but I think empty base classes always have a
> size of zero under VC++).
>
> As far as the results of dynamic_cast and examining the 'this' pointer
> values: You have to be very careful when second-guessing the compiler.
> In particular, in the case of VC++, a base class may appear to have two or
> more different values of 'this' depending on how and where you examine it.
> This is due to 'this pointer adjustments' that are applied to ensure that
> a member of C1 can always call another member of C1 without adjusting the
> aparent value of the 'this' pointer.
>
> I'd suggest you put the code back the way you had it originally, and if it
> doesn't work, post a bit more detail about how you're determining that it
> doesn't work - because in all likelihood, it's a coding error on your
> part. Multiple and Virtual inheritance works - and so does dynamic_cast
> (modulo that bug I mentioned with dynamic_cast from the constructor).
>
> -cd
>
>



Re: dynamic_cast is shite! by Bonj

Bonj
Sat May 07 05:39:55 CDT 2005

Thanks for confirming this - that's my reason for thinking it's shite!
I either need something that changes the values automatically, or for the
values to stay the same! Don't know whether that's expecting too much, but
then I have got to bite the bullet and make it simpler anyway as the more
code that goes in, the more cumbersome the code gets, so I think MI is a bad
thing for this project anyway.

"Michael K. O'Neill" <MikeAThon2000@nospam.hotmail.com> wrote in message
news:eaXkvznUFHA.3244@TK2MSFTNGP15.phx.gbl...
>
> "Bonj" <a@b.com> wrote in message
> news:edytZrmUFHA.3176@TK2MSFTNGP12.phx.gbl...
>
>> ... printf(this) in the constructors of them they all get different
>> values, e.g.
>> A will be 0x12fec0,
>> B will be 0x12fec4,
>> C will be 0x12fec8,
>> D will be 0x12fecc, ..etc.
>>
> ...
>> D* pd = dynamic_cast<D*>(pa);
>> // then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!
>
> dynamic_cast doesn't change the value of an object; it only changes the
> way
> the compiler interprets it.
>
>



Re: dynamic_cast is shite! by Carl

Carl
Sat May 07 08:32:29 CDT 2005

Michael K. O'Neill wrote:
> "Bonj" <a@b.com> wrote in message
> news:edytZrmUFHA.3176@TK2MSFTNGP12.phx.gbl...
>
>> ... printf(this) in the constructors of them they all get different
>> values, e.g.
>> A will be 0x12fec0,
>> B will be 0x12fec4,
>> C will be 0x12fec8,
>> D will be 0x12fecc, ..etc.
>>
> ...
>> D* pd = dynamic_cast<D*>(pa);
>> // then d ends up as 0x12fec0, NOT 0x12fecc as I was hoping!
>
> dynamic_cast doesn't change the value of an object; it only changes
> the way the compiler interprets it.

Not so. In a multiple-inheritance/virtual inheritance case, dynamic_cast
may produce a different 'this' pointer value. For that matter, so may
static_cast.

-cd



Re: dynamic_cast is shite! by Tom

Tom
Mon May 09 04:49:46 CDT 2005

Bonj wrote:
> Thanks for confirming this - that's my reason for thinking it's shite!
> I either need something that changes the values automatically, or for the
> values to stay the same! Don't know whether that's expecting too much, but
> then I have got to bite the bullet and make it simpler anyway as the more
> code that goes in, the more cumbersome the code gets, so I think MI is a bad
> thing for this project anyway.

dynamic_cast works fine, and adjusts pointer values as required:

#include <iostream>
struct A{virtual ~A(){}};
struct B: virtual A{};
struct C: virtual A{};
struct D: B, C{};

int main()
{
D o;
A* a = &o;
B* b = dynamic_cast<B*>(a);
C* c = dynamic_cast<C*>(a);
D* d = dynamic_cast<D*>(a);
std::cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' << &o <<
'\n';
}

Why do you think it doesn't work?

Tom

Re: dynamic_cast is shite! by Bonj

Bonj
Mon May 09 12:16:25 CDT 2005

> Why do you think it doesn't work?

Because it didn't work in my particular example. I was essentially looking
for suggestions as to a reason why it wouldn't work for me, not for a proof
that it does work at all.



Re: dynamic_cast is shite! by Tom

Tom
Tue May 10 03:52:39 CDT 2005

Bonj wrote:
>>Why do you think it doesn't work?
>
>
> Because it didn't work in my particular example. I was essentially looking
> for suggestions as to a reason why it wouldn't work for me, not for a proof
> that it does work at all.

It does work in your example! If you can't get it to work in your code,
you're doing something wrong and should post a cut down but compilable
version of your code.

#include <iostream>

class IReg {public: virtual ~IReg(){}};
class IWin : virtual public IReg {};
class IChildWin : virtual public IReg {};
class IODable : virtual public IReg {};
class WPWin : public IWin {};
class SplitWin : public WPWin, public IChildWin {};
class ODCombo : public IWin, public IChildWin, public IODable {};
class DPWin : public WPWin {};

int main()
{
ODCombo odCombo;
IReg* p1 = &odCombo;
IChildWin* p2 = dynamic_cast<IChildWin*>(p1); //down cast
IODable* p3 = dynamic_cast<IODable*>(p2); //x cast
void* baseAddress = dynamic_cast<void*>(p1); //base address cast

std::cout << baseAddress << ' ' << p1 << ' '
<< p2 << ' ' << p3 << '\n';
}

Tom