Components should register themselves with the appropriate system. You could do this in the constructor/destructor, though I'd highly recommend some explicit OnCreate() and OnDestroy() methods or some such.
You'd have something like so:
void Renderable::OnCreate() {
g_Renderer->RegisterRenderable(this);
}
void Renderable::OnDestroy() {
g_Renderer->UnregisterRenderable(this);
}
Your Foo class, going with your explicit inheritance-based composition, would then just have:
void Foo::OnCreate() {
GameObject::OnCreate();
Renderable::OnCreate();
}
void Foo::OnDestroy() {
GameObject::OnDestroy();
Renderable::OnDestroy();
}
That said, I don't particularly like the inheritance-based approach you have. It destroys one of the most important parts in my opinion of the component-based design approach: data-driven design.
Instead of making a bunch of specific hard-coded classes that combine components, you can take an approach where a GameObject is just a container of Component objects. This can range from the simple literal interpretation where GameObject is a class that actually has some kind of container of Component objects to an extreme abstraction where GameObjects are just identifiers that relate Component objects together, or you can do something more reasonable in between.
Going with the simple approach, take something like so:
class IComponent {
public:
virtual void OnCreate() = 0;
virtual void OnDestroy() = 0;
};
class Renderable : public IComponent {
public:
virtual void OnCreate() { g_Renderer->Register(this); }
virtual void OnDestroy() { g_Renderer->Unregister(this); }
};
class GameObject {
std::vector<IComponent*> m_Components;
public:
~GameObject() {
foreach (IComponent* cmp : m_Components) {
cmp->OnDestroy();
delete cmp;
}
}
template <typename Type>
void AddComponent() {
m_Components.push_back(new Type());
m_Components.back()->OnCreate();
}
template <typename Type>
Type* GetComponent() {
foreach (IComponent* cmp : m_Components) {
Type* typed_cmp = dynamic_cast<Type*>(cmp);
if (typed_cmp != nullptr)
return typed_cmp;
}
return nullptr;
}
};
Obviously that's hardly the most efficient implementation, but it gets the point across.
With an implementation like that, you can read in a data file that describes your objects. A game designer can use your game editor (or a text editor, if you haven't put in the time to make a useful editor) to compose objects as needed, without needing to go bug a developer and wait for a new build just to get some new behavior.
Even if there's not much need for finding new crazy combinations of components (but there is, especially once you allow scripts to define new components, so that you aren't stuck with the usual component-based engine with its "five C++ components and then helter skelter in script management" brilliance), it's at least handy for a designer to be able to add or remove components at runtime. Say that you had created two classes, StaticMeshDecoration and StaticMeshCollidable, the latter of which has a PhysicsBody component. In your editor, it would be really lame if a designer had created a StaticMeshDecoration, decided it needed physics, and then had to delete the object and recreate/reconfigure it all over as a StaticMeshCollidable.
On a final unrelated note, don't have a virtual method render on Renderable. It's not the individual object's job to render things. The whole point of having a Renderer object is that it takes the data of the renderable objects and then intelligently and efficiently figures out how to render the scene best. You should have a handful of specific Renderable component types that individually register themselves in the appropriate data structures in your renderer as meshes with all appropriate metadata (materials, shaders, etc.).
GameObject
andRenderable
sound pretty heavy. \$\endgroup\$