Skip to main content
gamedev.net
🔒 Locked

Implicit cast between pointers

Started by zeratulman 5 replies 1.2k views
Original Post
zeratulman
zeratulman
We're changing our software to run on multiple platforms(by platform I don't mean OS, but a software that our software runs on top of) that have very similar API's. I'm looking for a way to implement an implicit cast between pointers.

Our software originally looked like:

void f(A* x) {};
//........
B* y;
f(y);

Classes A and B are platform specific. The above code used to work since we had:

class A {};
class B : public A {};

In our new code, we cannot use classes A and B (since they are platform specific), and trying to run the code on some other platform wouldn't work since the new platform doesn't have classes A and B. Instead, it has classes C and D that basically do the same thing, but have a different name.

Our solution (which has been very much debated) is to make a wrapper over the 2 platforms like so:

#ifdef PLATFORM1
class xA : protected A
#else
class xA : protected C
#endif
{}

#ifdef PLATFORM1
class xB : protected B
#else
class xB : protected D
#endif
{}

This would be the general architecture of the wrapper.
In our code, function f becomes:

void f(xA* x) {};
//.......
xB* y;
f(y);

This obviously doesn't work any more, since xB is not derived from xA. What does work is having an explicit cast:

f((xA*)y);

However, we don't want to write this explicit cast everywhere in our code (very very much work). Instead i'm looking for a way to make this cast be called automatically.

Conversion constructors or cast operators would only work if the function were taking an argument of the respective type, not a pointer to an instance of the class. Overriding the function f to take an argument of type xB would be even more work than explicit casting since there are a lot of classes and even more functions. One other suggestion i found was making a function

f(B* x). This in principle works since both xA and xB are derived from B, however the function would only make sense on the first platform.

Any suggestions? Please reply only if you know how to do this, non-constructive criticism is not helpful. We have really worked hard on our architecture and it DOES work, we just want to get rid of the extra overhead.
Hodgman
Hodgman
So on platform 1 you've got A and B (and B inherits A), and on platform 2 you've got C and D (and D inherits C).

If so, can you do this?
#ifdef PLATFORM1#include "platform1.h"typedef A xA;typedef B xB;#else#include "platform2.h"typedef C xA;typedef D xB;#endifvoid f(xA* x) {};xB* y;f(y);//works, either because D inherits C, or because B inherits A.
Quote:
Original post by zeratulman
... doesn't work any more, since xB is not derived from xA. What does work is having an explicit cast:

f((xA*)y);
If y doesn't inherit from xA, then isn't forcing that cast to occur quite dangerous? Your function f thinks it's receiving a pointer to an xA object, but it's not.
This is one reason I prefer the C++ casts instead of these C-style casts. In this case, you'd first try to perform a static_cast, but the compiler would complain about the lack of inheritance, so then you'd be forced to write reinterpret_cast, which shouts out to everyone that you're doing something invalid/dangerous with pointers on purpose.
zeratulman
zeratulman
The typedefs don't really work since not all functions have the same name.
For example in class A you have f() and in class C you have g() which do the same thing. In class xA you would have h() that calls either f or g depending on the platform.
You're right, this would usually be a dangerous approach but it works for us and it's relatively safe since we know exactly what we're dealing with. It's tested and it does work.
Hodgman
Hodgman
In that case (the two platforms not having the same interface) I'd use a composition for your wrapper, instead of inheritance.
class xA{public:#ifdef PLATFORM1  typedef A* AHandle;#else  typedef C* AHandle;#endif  xA( AHandle h ) : internal(h) {}protected :  AHandle internal;};class xB : public xA{public:#ifdef PLATFORM1  typedef B* BHandle;#else  typedef D* BHandle;#endif  xB( BHandle h ) : xA(h) {}protected:  BHandle DownCast() { return static_cast<BHandle>( internal ); }};
zeratulman
zeratulman
Agreed, this would be a better solution, but the current architecture is already built and not subject to change. I've also been a advocate of what you just suggested, unfortunately my method was not adopted and now we have to work with this. :)

I did come up with a partial solution though:

void f(xA* x) {};
#ifdef PLATFORM1
void f(A* x) { f((xA*)x); }
#else
void f(C* x) { f((xA*)x); }
#endif

In principle this should work when passing an argument of type xB since xB->B->A and xB->D->C but it doesn't in our case since we derive from B and D using protected. I tested this and if we would derive using public, this would work. Sadly, this also isn't subject to change.

A solution for this would solve the bigger problem.
Cheers.
ppgamedev
ppgamedev
Cannot you extend your proposed solution?
void f(xA* x) {};void ff(xB* x) {};#ifdef PLATFORM1void f(A* x) { f((xA*)x); }void f(B* x) { f((xA*)x); }void ff(B* x) { ff((xB*)x); }#elsevoid f(C* x) { f((xA*)x); }void f(D* x) { f((xA*)x); }void ff(D* x) { ff((xB*)x); }#endif
zeratulman
zeratulman
Not really. Only having the base classes there would help, as there would be too much work adding all of the rest (there's a lot of them).

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.