Skip to main content
gamedev.net
🔒 Locked

Inheritance + RTTI

Started by kavika Mar 5, 2004 at 9:58 PM 8 replies 950+ views
Original Post
kavika
kavika
Have a question, tho it requires some BG: I've got two classes, here: #ifndef RENDERER_H #define RENDERER_H // It's really a lot longer than this class surface { public: surface (); virtual ~surface (); virtual void somefunc () = 0; }; class image; // defined elsewhere class renderer { public: renderer (); virtual ~renderer (); virtual surface& create_surface (image& image) = 0; virtual void render_surface (surface& blah) = 0; }; And I have a .DLL that derives from this interface #ifndef INCLUDED_SDL_RENDERER_H #define INCLUDED_SDL_RENDERER_H class sdl_surface : public surface { public: sdl_surface (); ~sdl_surface (); void somefunc (); }; class sdl_renderer : public renderer { public: sdl_renderer (); ~sdl_renderer (); sdl_surface& create_surface (image& image); void render_surface (surface& blah); }; Here's the problem I have: in render_surface, how to convert it back to a sdl_surface. I've come up with two options: 1) use dynamic_cast, and if I don't get something valid, either no-op, or throw an exception 2) implement a magic cookie system (using unsigned ints) to refer to the surfaces, and storing them in a map -> std::map (Well, I've got a special pointer class and not a sdl_surface, and a typedef instead of unsigned int, but you get the point =) Wondering if there are any other options I haven't considered, cause I don't think RTTI is a good option (dynamic_cast). Also, instead of the magic cookie system, I'd rather have users just keep track of pointers, if possible. They're going to be using them to manipulate the surfaces directly, so that would be simpler, and they wouldn't have to come up with enums, or me come up with "unique random numbers" The only reason I'm using an inheritance scheme is since the "renderer" will be loaded from a .dll, and there's no way for the main library to know which renderer will be loaded. I can't think of any non-inheritance scheme to make this work, that's simple, and doesn't involve crazy hacks... Of course there's always the "all implmentations known at compile time" deal, along with simple switch statements for which to use, but that takes some of the fun, and purpose, out of coming up with a plugin system =) Anything I've missed? Any bright ideas? And no comments, please, on the speed this particular approach disallows, or how idiotic it is. I still wanna do it, and see for myself exactly how slow it'll probably be =) [edited by - kavika on March 5, 2004 10:59:38 PM] [edited by - kavika on March 5, 2004 11:00:29 PM]
SiCrane
SiCrane
Why do you need to do this cast in the first place?
SiCrane
SiCrane
Will you ever have more than one renderer in existance at any point or more than one type of derived surface class instantiated at once?
SiCrane
SiCrane
While the client only needs to be provided with the renderer''s abstract type, you can maintain a pointer to the renderer''s concrete type in the dynamic library, since you only have the one renderer. If you migrate the render_surface() function to the surface class as a virtual function, it can use the concrete type of the renderer to grab the screen buffer and blit from it''s own surface data.

Or you could just use static_casts in the render_surface() function, and use an assert() to check against the pointer returned by a dynamic_cast in debug mode. Since you only have one set of related types, this should be reasonably safe.
JohnBolton
JohnBolton
How about using the visitor design pattern like this?

class surface
{
public:
surface ();
virtual ~surface ();

virtual void render() = 0;
};

class renderer
{
public:
renderer ();
virtual ~renderer ();

virtual surface& create_surface (image& image) = 0;
};

class sdl_surface : public surface
{
public:
sdl_surface ( sdl_renderer & renderer ) : m_renderer( renderer );
~sdl_surface ();

void render() { m_renderer.render_surface( *this ); }
private:
sdl_renderer & m_renderer;
};

class sdl_renderer : public renderer
{
public:
sdl_renderer ();
~sdl_renderer ();

sdl_surface& create_surface (image& image) { ... new sdl_surface( *this ); ... }
void render_surface ( sdl_surface& blah);
};


To render a surface:

surface & s = renderer.create_surface( image );
s.render();


John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
kavika
kavika
You know, I spent $50 on the GoF book, you''d think I''d have at least read it Checking out the chapter on that pattern now.. the diagram looks so far pretty much like my hierarchy, too.

Thanks guys =)
kavika
kavika
Seems actually to be a variation on the visitor pattern.

Instead of the client creating concrete visitor classes to feed to the concrete nodes, all the visiting happens in the background, via the concrete object setup. The visitor also is simultaneously the program storing the nodes. Also, the single visitor is locked into the node on creation.

I really don''t need all the benefits of the visitor pattern touted by the GoF book, and this particular setup seems not to have the benifits they offer. However, the modifications you described seem to solve _this_ problem neatly.
kavika
kavika
ACTUALLY, since I only need one renderer at a time, I could make it a singleton class, and save the per-surface storage cost, and probably some other tricks like this =) Bleh. When I actually think out problems, it helps a lot.

Okay, I think I definately have my answers now.

Thanks a lot!
Cheers

Topic Locked

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

Sign in to reply to this topic.