Casting up to a derived class [solved]

Started by
17 comments, last by Valor Knight 17 years, 5 months ago
Quote:Original post by Fruny
There's also the question of why external code should ever need access to the HWND. In most cases, only member functions should need to use it.


DirectX requires it to be passed when initializing a direct3d device. That's the only case I think it's ok to dynamic_cast. Even if you do whatever preprocessor tricks, you're still going to have to call

WinHandle.HWND

where you need it externally (which should only be one other place like directx), which is basically assuming that it's a windows class. That doesn't fix this problem at all, though I think it's good to use preprocesser directives for cross-platform code.
Advertisement
Yea, Im passing it to a direct x device.

Im not using dynamic_cast nor need it now with the preprocessor commands
Just in the base class I have a getwindowhandle.

Actually now that I mention it, I am going to derive a class from a base window class for a Windows version of initing, ect... should I just have the class in preprocessor so there is only 1 window class and the preprocessor picks the correct one?
There is no life without honor
If you have access to the base class definition, then dynamic_cast is not required:

class Base {public:  virtual class Derived &asDerived() {    throw std::bad_cast(...); // or another appropriate exception.  }};class Derived : public Base {public:  Derived &asDerived() {    return *this;  }}


Of course, if this conversion is very infrequent, does not make any sense as part of the design (it does, after all, break the open/closed principle in most cases) or is required in a similar fashion for many other classes, then dynamic_cast is a better solution.
Quote:Original post by Anonymous Poster
@joanusdmentia:
That's a really good idea. Then just #ifdef around the headers you need.


No #ifdef's are required at all. The majority of your code will only include the 'PlatformWindow.h' file (which contains no platform-specific types). The parts which are platform specific (eg. the window's implementation, Direct3D, etc) will then include the appropriate platform specific header (eg. Win32Impl.h). By keeping each platform's implementations in different .cpp files you can compile and link only the source files for the current platform.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
I seem to recall that dynamic_cast has to do some extra work if you're using multiple inheritance (or the other crazy inheritance types). I'm not sure if it does this extra work if the compiler suspects that you only use single inheritance...

If you're using single inheritance, most cases I've seen will work properly if you compare the first pointer-sized section of data in the object against the same bytes in an object that you KNOW is your target class (you can make a dummy instance - I wish C++ had a construct to get direct access to the vtable pointer without a nasty hack like this)


ToohrVyk's system is a lot cleaner than this hack though. You have to maintain the base class more than usual, though.
Quote:Original post by Nypyren
(you can make a dummy instance - I wish C++ had a construct to get direct access to the vtable pointer without a nasty hack like this)


There is no such thing as a vtable pointer in C++, citizen.

The output of certain compilers may include a vtable pointer as an implementation of dynamic binding of methods. Other compilers, or certain virtual machines, may also implement dynamic binding of methods through a hash system or by decorating objects with their methods directly. While you can expect the usual C++ compilers to use a virtual table, you cannot assume that this is the case, lest you explicitly violate the C++ Standard and end up with undefined behaviour.

Also note that your hack can only be expected to work if the object is of the expected type. In particular, if C is-a B is-a A, then a reference to A storing a C will not be converted to a B this way. dynamic_cast and a virtual method would work here, however.

As for the work done by dynamic_cast: it's mostly a type lattice traversal (although it's not a lattice, but let's assume it is) which checks that the required type is a supertype of the dynamic type. This traversal is linear (straight up) when not using multiple inheritance, but it may need to look for several paths when multiple inheritance is used.
dynamic_cast<>() requires c++ RTTI-system to be enabled. This afaik intoduces some overhead not only to your specific class but to all classes in your code. If you realy are absolutely sure you have a class of type B ( assuming B extends A ) you could also use reinterpret_cast<>(). I must admit, that this technique is a bit durty but if you only need it for 1 or 2 classes, i think its a good tradeof.

To ensure that your class is a B, you could simply write your own little RTTI for that class.

I personally though can't think of many situations where you really would require dynamic_cast<>(), since you have got a much more powerfull and elegant toy (virtual functions) to solve all of these problems. Just try to sit down a few minutes and rethink your design. As for platformspecific handles you could simply wrap them up, which is basically what joanusdmentia did.


t0}{!c
Quote:Original post by t0Xic
dynamic_cast<>() requires c++ RTTI-system to be enabled. This afaik intoduces some overhead not only to your specific class but to all classes in your code.


It's true: lattice traversal information is added to each class. This results in a slightly larger executable. However, speed and runtime memory usage are unaffected.

Quote:
To ensure that your class is a B, you could simply write your own little RTTI for that class.


This would most probably result in time and per-instance memory overhead for that class, not to mention that it would be unsafe. Using virtual functions to perform typecasts (as I outlined above) has no such overheads, is typesafe and requires less work.

Quote:Original post by joanusdmentia
Quote:Original post by Anonymous Poster
@joanusdmentia:
That's a really good idea. Then just #ifdef around the headers you need.


No #ifdef's are required at all. The majority of your code will only include the 'PlatformWindow.h' file (which contains no platform-specific types). The parts which are platform specific (eg. the window's implementation, Direct3D, etc) will then include the appropriate platform specific header (eg. Win32Impl.h). By keeping each platform's implementations in different .cpp files you can compile and link only the source files for the current platform.


I like that method. I think I will use it in conjucnction with a ifdef for a handle. I dont want to have to parse that out in d3d or other stuff. Who knows may even do your handle method. Thanks for the idea.
There is no life without honor

This topic is closed to new replies.

Advertisement