• Advertisement
Sign in to follow this  

Casting derived classes from void*

This topic is 4348 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
Quote:
Original post by Xai
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).


Even then, one could create an object base class from which all objects inherit. Or, better yet, if only a certain amount of classes may be passed as mentioned above, make all of them inherit, directly or indirectly, from a common base class which can then be used.

Also, don't forget:

class A { public: virtual ~A( ) { } };
class B { public: virtual ~B( ) { } };

// There are situations where this conversion is possible:
// An object can exist that is both A and B.
B* Frobnicate(A* a) {
return dynamic_cast<B*>(a);
}



Share this post


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

read that sentence again ... and then read the line BELOW it in my original post ...

IF you already have a common base class, you should NOT be using void *. That's all I said, and it is indisputable. You may not loose much by using void *, but you gain absolutely nothing.

If you don't have a common base, then you use void* - that's what it is for - a universal pointer).

As for dynamic_cast, it is a type-safe cast, it sets the result to null if the object is not actually derived from the class given. But it only works on heirarchies of related (common base) objects.

so assume you have 5 classes, B, D1, D2, D3 and X - where B is the base class of D1, D2 and D3 and X is not related.

B* obj = ??
D2* objectD2 = dynamic_cast<D2*>(obj);

objectD2 will be null (0) if obj was NOT derived from class D2.

You cannot get this behavior using void * without your own custom type mapping code (why rewrite the standard).

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
IF you already have a common base class, you should NOT be using void *. That's all I said, and it is indisputable.


Alright. I'm not trying to dispute with you. I apreciate your help. I was just asking you the reason why things should be like you said, because I don't know it.

I've read that to use dynamic_cast I RTTI must be enabled. Is it enabled by default? I'm using gcc.

Thanks. And rest asure I'm not trying to argue with you. I'm just looking for advice.

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
I've read that to use dynamic_cast I RTTI must be enabled. Is it enabled by default? I'm using gcc.
Yep. Most compilers are smart enough to turn on RTTI if they encounter a typeid() or dynamic_cast<>, or issue an error if they are used with RTTI off.

Share this post


Link to post
Share on other sites
In this case I think the service model is too generic.
You may want to consider a core that has dedciated accessor functions for the sub-systems.
Will you ever use CBase without the renderer? Becuase your design is made for that type of scenario.
When you design classes you want to aim for the sweet-spot, only as complex as they need to be.

IRenderer* Core::render();
IVocalizer* Core::vocalizer();
etc...

[Edited by - Shannon Barber on March 29, 2006 8:55:01 PM]

Share this post


Link to post
Share on other sites
Using void* in combination with multiple inheritance can lead to very nasty bugs.
Example:

#include <iostream>
using namespace std;
struct Interface1 {};
struct Interface2 {};
struct Derived: public Interface1, public Interface2 { };

int main() {
Derived obj;
void* p1 = (void*)&obj;
Interface2* p2 = (Interface2*)p1;
cout << p2 << " " << (Interface2*)&obj << endl;
}





This will print two different values (at least on my machine). This is because the compartments for different superclasses start at different points in memory. The C++ compiler will take care of normal upcasts, but it can't know what a void pointer points to in general, so casting to void* means losing information. So imagine what happens if you call a member function on *p2 ...

Share this post


Link to post
Share on other sites
If you were to do a lot of void* casting to other types, basically something gone wrong. (Over engineered?)

Btw, I agreed with Xai: "In any heirarchy in C++ with a common base class you would NEVER use a void *."

Share this post


Link to post
Share on other sites
Quote:
Original post by Shannon Barber
In this case I think the service model is too generic.
You may want to consider a core that has dedciated accessor functions for the sub-systems.
Will you ever use CBase without the renderer? Becuase your design is made for that type of scenario.
When you design classes you want to aim for the sweet-spot, only as complex as they need to be.

IRenderer* Core::render();
IVocalizer* Core::vocalizer();
etc...


The application I've in mind is kind of a server into which you can plug services and programs contained in shared libraries. That's the reason why I made it that generic. I would like to be able to use it for games as well as for any other kind of application with minimal recompiling.

I've been informing myself about dynamic_cast and it introduces quite a bit of troubles when used with shared libraries... but all of them can be solved compiling with the proper options.

Based on what I've read and what it has been said here, I understand that the safer aproach is to use dinamic_cast. Any other work around would introduce a lot of nasty and pretty slow coding that I'm not willing to face at this time, or to re-design in the future.

Anyway, if someone had any other idea, I'll be pleased to hear it.

tnx.

Share this post


Link to post
Share on other sites

Still, somewhere in your code you will have to cast from void* to a specific IFoo*, so I can see no reason why your factory shouldn't return base pointers.


interface IRenderer {};
interface IFoo {};
interface IFilter {};

// ... get all your plugin names ..

std::vector<std::string> myRendererPlugins = myRegistry.readRendererPlugins();
std::vector<std::string> myFooPlugins = myRegistry.readFooPlugins();

// ... instantiate the objects and get interfaces (not void*)
IRenderer* renderer = myFactory.getRenderer( *(myRendererPlugins.begin()) );
IFoo* foo = myFactory.getFoo( "FooBarUltimate" );

// ...


Again, I can't see why your factory should be over-generic, as you'll have to be concrete sometime anyway.. or did I miss something? Are the interfaces not known beforehand?

[Edited by - Konfusius on March 30, 2006 10:56:09 AM]

Share this post


Link to post
Share on other sites
Well, I solved it without dinamic_cast. I realised that since I store a pointer to the shared library in the service object I can access the function that builds_up/returns the service instance from there.

I created a templated function in the IServices class that takes the name of the service as a paramter. It searches for the service to see if it is loaded. If it is, then it access the shared library from it and from there the function in the shared library that returns an instance to the derived object.

I don't really need it to be teh faster because I won't be using it beyond the intialization of the objects that will use it.

Quote:
Original post by Konfusius
Again, I can't see why your factory should be over-generic, as you'll have to be concrete sometime anyway.. or did I miss something? Are the interfaces not known beforehand?


The engine, I mean, the engine for *anything* can be built on top of this core. That's why I don't want it to rely on services that might not be needed in some specific app. I can extend the factory any time I want so I don't really need to hardcode interfaces to services there.

The base factory only has methods for creating the objects needed by the server, like IServices, IFatalError, ISharedLib, etc.

The server's primary implementation has default concrete classes so it can have a default behavior: For example CFatalError that is accesed through IFatalError prints __FILE__, __PRETTY_FUNCTION__ and __LINE__ with a message to stdout, calls IServer::Terminate() and exits the app. I can extend this class so it can use a service for a windowed system and print information to a specific kind of window, or use a renderer to draw the same message with some graphic library.

I'm having lot's of fun taking this aproach, and I'm learning a lot too. It'll probably be quite slow compared to a raw C coded engine, but, by the time I finish it, if ever, machines will be so fast that nobody will notice :P

Share this post


Link to post
Share on other sites
didn't mean the ALL CAPS as yelling either (well I kinda did, but it was a silly over reaction on my part) ... I mainly meant them as emphasis so you would see the parts I thought we're most relevant ... I wish italics we're as quick and easy to type as caps, then I wouldn't have to be such a jerk while helping people sometimes :)

Share this post


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

  • Advertisement