Jump to content
  • Advertisement
Sign in to follow this  
allsorts46

Casting by overloading

This topic is 4873 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This isn't really a problem, but I'm just curious if it can be done. Basic background is that I am loading some DLLs, and calling a function in them which returns a pointer to an instance of a class. These can be of different types in different DLLs, but the function used to return the pointer must always have the same return type. For as long as I cast it to the type I expect it to be, everything's working fine. For example: Render2D* RenderDevice = (Render2D*) RenderExtension->GetEntity(); If I take the cast away: Render2D* RenderDevice = RenderExtension->GetEntity(); I get a compile error telling me a cast is required. I know that's to be expected, and it might not be good practice to remove it, but I'd like to try. I searched on the subject for a while, and found some places suggesting that it could be done by overloading a 'cast operator' in the class, telling it how to do the conversion. The return type of GetEntity() is Object* which is another class that is pretty much empty. I added to it: operator Render2D* () { return (Render2D*) this; } Which compiles fine, but doesn't affect the situation in any way. I've also tried it the other way round; I've made the return type of GetEntity() to be void*, and overloaded the assignment operator of Render2D to accept a void*, but that too had no effect at all. I've also tried this when Render2D is derived from Object and when it's not. Again, no difference. Everything I try appears to be accepted as valid, but does absolutely nothing. Hope I explained that okay. And again, I know most people are likely to tell me I just shouldn't be doing it, but I'd like to try anyway. Also, if it wasn't clear, the return type of GetEntity can't be Render2D, because it can return classes of many types (Render3D, World2D, Physics2D etc). Any help on the subject would be appreciated!

Share this post


Link to post
Share on other sites
Advertisement
From what I understand the casting operators must be used upon [or rather to] actual objects. Since the assignment is being made via pointers it probably ignores the casting.

Another way would be to overload GetEntity() with the various returns:

... RenderExtension{
Render2D *GetEntity(Render2D);
Render3D *GetEntity(Render3D);
}


Though that's a little unwieldy and annoying. Personally, I don't see anything wrong with the explicit casting [though others will recommend the use of C++ casts over C-style] as long as you document in the function that it must return the various types. Though I wonder if there isn't a better design that wouldn't eliminate the need in the first place.

Share this post


Link to post
Share on other sites
Quote:
Original post by Telastyn
Another way would be to overload GetEntity() with the various returns:


That's a good idea... GetEntity() is actually only a function pointer in a struct, and it won't let me define that multiple times, but I could easily wrap it in another function and overload that one. I imagine it'd add a bit of overhead, but it's only called once, so that doesn't matter, and I can't see any reason why it should be unsafe. Thank you!

EDIT: Tried it, works perfectly. No more complaints from the compiler.

Share this post


Link to post
Share on other sites
C++ doesn't let you overload by return type.

ObjectA* GetObject();
ObjectB* GetObject();

doesn't work, sadly.

an option could be

void GetObject( ObjectA** ppObjectA );
void GetObject( ObjectB** ppObjectB );

Which would work since you are overloading by argument, not return type.

Strangely enough, if I try using templates, it works, even though the resulting generated code should be the same as above:



class A;
class B;

void GetObject( A** ppA )
{
*ppA = reinterpret_cast< A* >( GetBaseObjectToCast() );
}

void GetObject( B** ppB )
{
*ppB = reinterpret_cast< B* >( GetBaseObjectToCast() );
}

template<class T>
T* GetObject()
{
T* p;

GetObject( &p );

return p;
}

void Func()
{
A* a;
B* b;

a = GetObject<A>();
b = GetObject<B>();
}



I'm confused why this works, but it does. I tested it under MSDev 2003, so it may not work on other compilers.

The two functions GetObject<A>() and GetObject<B>() should result in code that is equal to A* GetObject() and B* GetObject(), which failed earlier. Maybe the code is being inlined immediately and so the function never really exists; it simply expands to GetObject( A** ppA ) and GetObject( B** ppB ).

None the less, hope that helps.

- S

Share this post


Link to post
Share on other sites
In the example with template, you define one function template and declared multiple instances of template functions.

Kuphryn

Share this post


Link to post
Share on other sites
Quote:
Original post by Sphet
Strangely enough, if I try using templates, it works, even though the resulting generated code should be the same as above:

void Func()
{
A* a;
B* b;

a = GetObject<A>();
b = GetObject<B>();
}

I'm confused why this works, but it does. I tested it under MSDev 2003, so it may not work on other compilers.


Well umm, maybe because those are two completely different functions? There's the template argument that completely uniquely identifies the two functions; there's no ambiguity whatsoever. That's exactly the same as if you did this:

A *GetObject_A();
B *GetObject_B();

A *a = GetObject_A();
B *b = GetObject_B();

except of course with templates you can instantiate an arbitrary number of functions from the one template.

Share this post


Link to post
Share on other sites
After I just read what Sphet said about C++ not allowing you to overload by return type, I realised I'd just gone and declared it once and assumed it was all fine, which of course it would be. Indeed, adding another one causes errors again, so that doesn't work.

Templates are a good suggestion, but I've had hours of toubles getting then to work between my main program and my dynamically loaded library - it refuses to link if the code is not all contained within the header, because otherwise they're not available to the DLL. I suppose since these would be small it wouldn't be too bad to keep the code in the header, but even then:

Render2D* RenderDevice = RenderExtension->GetEntity<Render2D>();

isn't really any different from

Render2D* RenderDevice = (Render2D*) RenderExtension->GetEntity();

Since the only point in this was to remove the need to specify the type twice, I haven't really got anywhere. I'm trying to get it so that anything related to the casting is hidden away from the final usage of the function. I want to be able to type:

Render2D* RenderDevice = RenderExtension->GetEntity();

and have the code somewhere else do the work of the conversion. I think just changing to overloading by argument would be the best idea so far, but to me that makes it less intuitive to use. Probably just preference, but I refer to recieve something as a return value, than pass something and have it 'filled' or whatever.

Ah well, thanks for the suggestions. If it's not possible to cover it all up it's not important, I'll just go on using the original cast. Just trying to make the interface to the library as simple as possible to use.

Share this post


Link to post
Share on other sites
The only thing I can think of beyond that is a system where you query for a type, and then hold onto that in your client code.

Does your RenderDevice change often, or at all, during runtime?

When you initialize D3D you get a device pointer you are expected to hold onto until you are finished using it. Can you not use the same thing? You avoid the casting, except in the initial capture of the device.

It doesn't solve your problem, but it also avoids the need to call through the pointer every time youi need to use something.

Render2D* g_pRenderDevice;


void OnInit()
{
g_pRenderDevice = reinterpret_cast<Render2D*>( RenderExtension->GetEntity() );
}


Polluting the global namespace is almost always something to keep away from, but a global render device pointer does make sense to me.

Best of luck,


- S

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Have you thought about hiding it in the constructor....
Although that may override something else you have in place, you may have to overload the class constructor to get it to work.

Share this post


Link to post
Share on other sites
Sphet:

It's not actually in the global namespace, I just simplified it a lot to post here. I'm also only retrieving the pointer once, which is why even if I can't find a solution, it's not a big deal - everything works, I'm just trying to make it look tidier.

Without any using namespaces, it looks like this:


XGE::Core::Extension* RenderExtension = XGE::Core::LoadExtension("XGEXT_Render2D_Allegro");
if(!RenderExtension) Die("Failed loading Render2D extension\n");

XGE::Graphics::Render2D* RenderDevice = RenderExtension->GetEntity();
if(!RenderDevice) Die("Failed getting Render2D device from extension\n");

// ...

XGE::Graphics::VideoMode* ModeList = RenderDevice->GetModes();


AP:

The problem with doing anything with the constructor is that there isn't really one I can use. XGE::Graphics::Render2D is only used as an interface, and in any case I'm only declaring a pointer to one. No instance of Render2D is ever actually created. The DLL passes back a custom class which is derived from that interface, in this case it's called AllegroDevice. Altering that class in any way doesn't help, because it only exists in the DLL, and any program that uses it doesn't know what it is - they only get to treat it as a Render2D*.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!