Jump to content
  • Advertisement
Sign in to follow this  
owl

Casting derived classes from void*

This topic is 4520 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

Is the following too ugly? Do you know a better/safer/neater way of doing this?
void* CBase::GetClass(string name)
{
  if ("CBase"==name)
    return this;

  return 0;
}

void* CDerived::GetClass(string name)
{
   void* retval = CBase::GetClass(name);
   if(!retval)
     if ("CBase"==name)
       retval = this;

  return retval;
}

Share this post


Link to post
Share on other sites
Advertisement
You should really be passing your strings as constant references.
If all the classes derive from one common base class, you can return that as a return type instead of void

Personally, I'd do it like this:

class CBase
{
// ...
virtual CBase* GetClass(const std::string& strName)
{
if(strName == "CBase")
return this;
return NULL;
}
// ...
}

class CDerived : public CBase
{
// ...
virtual CBase* GetClass(const std::string& strName)
{
if(strName == "CDerived")
return this;
return CBase;:GetClass(strName);
}
// ...
}


I.e. check if the derived class supports the interface, and if not, pass it off to the base class.

Share this post


Link to post
Share on other sites
Yes, that's a lot nicer.

But, I use void* in this case because the base class doesn't supply the functionality of the derived class. Specifically, it's a generic Service interface. So, to access the functionality of a specific service I need to get a pointer to the derived class directly.

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
Yes, that's a lot nicer.

But, I use void* in this case because the base class doesn't supply the functionality of the derived class. Specifically, it's a generic Service interface. So, to access the functionality of a specific service I need to get a pointer to the derived class directly.
In that case, you can stick with void*, or you could go the COM way, and force all services to derive from a base class. Even if it's empty, it still makes the code a little easier to read. It also gives you a place to have a function like GetClassName() which would return a string indicating the name of the class (for debugging, serialization, etc).

Share this post


Link to post
Share on other sites
This is a reasonable way to do QueryInterface style fetching of implementations.

I would probably wrap it in a template getter, and use typeid() instead of strings.


class InterfaceBase {
public:
template< typename T >
T * getInterface() {
return (T*)getInterface(typeid(T));
}
protected:
virtual void * getInterface(typeinfo const & ti) = 0;
};

void * InterfaceBase::getInterface(typeinfo const & ti)
{
return 0;
}

class CBase : public InterfaceBase {
protected:
void * getInterface(typeinfo const & ti ) {
if( ti == typeid(CBase) ) {
return this;
}
return InterfaceBase::getInterface( ti );
}
};

class CDerived : public CBase {
protected:
void * getInterface(typeinfo const & ti ) {
if( ti == typeid(CDerived) ) {
return this;
}
return CBase::getInterface( ti );
}
};


And, once you look at this implementation, you could see a simple way to wrap the implementation of getInterface() in a macro or two. (Two, if you want to be able to return delegates)

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
But, I use void* in this case because the base class doesn't supply the functionality of the derived class. Specifically, it's a generic Service interface. So, to access the functionality of a specific service I need to get a pointer to the derived class directly.


You do know that return type does not participate in function overload resolution, don't you?

You could just do something like the following.

class Base
{
virtual Base* GetClass(const string&);
};

class Derived: public Base
{
virtual Derived* GetClass(const string&);
};


That would avoid all that C-with-classes void* stuff.

On the other hand, usually any sort of hand-hewn RTTI is usually a big red flag that you need to rethink your design anyhey.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
or you could go the COM way, and force all services to derive from a base class. Even if it's empty, it still makes the code a little easier to read. It also gives you a place to have a function like GetClassName() which would return a string indicating the name of the class (for debugging, serialization, etc).


How's the COM way?

I derive all the services from a class IService, which is pretty much, a dummy interface. They are stored in a map<string, IService> in a IServices class.

When I need, say, a service for rendering I call:

IRenderer* p = (IRenderer*)Services->Service("Renderer")->Concrete();


Concrete() should return the last derived concrete class. I was thinking about parametrizing the concrete class one can access and I thought to make it like in the original post.

Do you feel this is a decent way of doing this? Tnx.

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
This is a reasonable way to do QueryInterface style fetching of implementations.

I would probably wrap it in a template getter, and use typeid() instead of strings.

[...]

And, once you look at this implementation, you could see a simple way to wrap the implementation of getInterface() in a macro or two. (Two, if you want to be able to return delegates)


I thought about using typeids at first, but somewhere in the middle of the implementation I changed my mind to strings for some reason I quite dont rememeber right now... I'm trying to make this as OCP as I can and to stay away of macros as much as I can too.

But I don't know how much I'm going to last with this philosophy :)

Share this post


Link to post
Share on other sites
In any heirarchy in C++ with a common base class you would NEVER use a void *.

The only time to use void * is when their is no common base.

In C++ you pass around the base class pointer and use dynamic_cast to see if it is a derived class object of a certain type (if necessary - which often isn't once the design is cleaned up).

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
In any heirarchy in C++ with a common base class you would NEVER use a void *.

The only time to use void * is when their is no common base.


Why should I NEVER use void*? Is it because I'm risking myself to cast an object to a wrong pointer? Does dynamic_cast save me from making the same mistake?

tnx.

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!