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
>
>