Sign in to follow this  
  • entries
    7
  • comments
    12
  • views
    5669

Abstract Interfaces

Sign in to follow this  
FunLogic

256 views

Abstract Interfaces


Lately I've been brushing up on some of the more advanced c++ topics. The book I've found really helpful in this is C++ for Game Programmers. Something that I've picked up from this book and really want to use in my current projects are Abstract Interfaces. Here's a quick example from the book that I've been playing about with to understand the idea of interfaces a little better.



// Abstract Interface that provides a rendering interface to
// derived classes
class IRenderable
{
public:
virtual void Render(void) = 0;

};

// Abstract Interface that provides a simple physics interface to
// derived classes
class IPhysical
{
public:
virtual void UpdatePhysics(void) = 0;

};

// Game Entity base class
class Entity
{
public:
virtual void Update(void) = 0;

QUERY_INTERFACE_BEGIN
QUERY_INTERFACE_END

};

// A Tree Game Entity (not to be mistaken for a tree data structure) this is one of
// those green things out the window. Has rendering capabilities
class TreeEntity : public Entity, IRenderable
{
public:
void Render(void);
void Update(void);

QUERY_INTERFACE_BEGIN
QUERY_INTERFACE_ADD(IRENDERABLE, IRenderable)
QUERY_INTERFACE_END

};

// A Player Game Entity has both physics and rendering capabilities
class PlayerEntity : public Entity, IRenderable, IPhysical

{
public:
void Update(void);
void Render(void);

void UpdatePhysics(void);

QUERY_INTERFACE_BEGIN
QUERY_INTERFACE_ADD(IRENDERABLE, IRenderable)
QUERY_INTERFACE_ADD(IPHYSICAL, IPhysical)
QUERY_INTERFACE_END

};






Using this setup I can store all of my game objects in a single array / vector / list. Iterate through them and at runtime decide whether or not I need to call Render() and / or UpdatePhysics(). Pretty neat, considering before this I was either using an isVisible boolean flag or storing visible objects in a seperate container. Here's a sample of these classes being used:


int main(void)
{
std::list entityList;

entityList.push_back(new TreeEntity());
entityList.push_back(new PlayerEntity());
entityList.push_back(new TreeEntity());
entityList.push_back(new PlayerEntity());

std::list::iterator itr;
for(itr = entityList.begin(); itr != entityList.end(); itr++)
{
void* pInterface;

(*itr)->Update();

pInterface = (*itr)->QueryInterface(IPHYSICAL);

if(pInterface != NULL)
{
IPhysical* pInst;
pInst = static_cast(pInterface);
pInst->UpdatePhysics();
}

pInterface = (*itr)->QueryInterface(IRENDERABLE);

if(pInterface != NULL)
{
IRenderable* pInst;
pInst = static_cast(pInterface);
pInst->Render();
}
}

system("pause");
return 0;
}






-- On a side note, I had to make a change to the code presented in the book in order to get it to work. I'm pretty sure it was correct but if someone could double check this for me it would be great. In the book, the QueryInterface() method is implemented just in the base class and isn't virtual, the only way I could get it to work was as follows:


#define QUERY_INTERFACE_BEGIN virtual void * QueryInterface(Interface interface) {
#define QUERY_INTERFACE_ADD(q, p) if(interface == q){p* inst = static_cast(this); return (void *)(inst);}
#define QUERY_INTERFACE_END return NULL;}




Sign in to follow this  


3 Comments


Recommended Comments

I bought that book on a whim one day, and it was probably the best thing that has ever happened to me programming wise.

Share this comment


Link to comment
By using dynamic_cast, I'm assuming you mean as opposed to using static_cast within the query function and when accessing the interface within my "game loop".

Performance for one thing, as static_cast performs no run-time type checks, it's got much less of a performance overhead than dynamic_cast. Sure dynamic_cast is a lot safer, and static_cast is really only advised for numeric data type conversions and when your absolutely sure that casting will work. But if this system was used to manage a game with hundreds of objects of a class derived from numerous interfaces - dynamic_cast would kill performance.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now