Function Pointer Signature Issue related to Inheritance

I'm programming a game engine and having an issue with the design of a function. The function will search a directory for a specific type of file, then use those files to build the proper graphics components.

For example, lets say I have the following:
Folder directory: ...\data\shapes\
files in 'shapes': circle.shp, square.shp, and readme.txt
The shape components will be built using the .shp files.
A call to the function would look like this:
LoadResources("data\\shapes\\", ".shp", Factory::BuildShape);

The graphics components
1
2
3
4
5
6
7
struct Component {};
class Shape : public Component {};
class Camera : public Component();
class Light : public Component();
class Mesh : public Component();
class Material : public Component();
class Texture : public Component();


Here are the functions used to build the various components.
1
2
3
4
5
6
   Shape* const Factory::BuildShape(std::string _file);
  Camera* const Factory::BuildCamera(std::string _file);
   Light* const Factory::BuildLight(std::string _file);
    Mesh* const Factory::BuildMesh(std::string _file);
Material* const Factory::BuildMaterial(std::string _file);
 Texture* const Factory::BuildTexture(std::string _file);


LoadResources() takes a function pointer as a 3rd parameter.
The function passed is used to construct the components.
1
2
void Graphics::LoadResources(std::string _dir, std::string _ext,
                             Component* (*BuildComponent)(std::string))


Would like to make calls like this.
1
2
3
LoadResources("data\\shapes\\", ".shp", Factory::BuildShape);
LoadResources("data\\meshes\\", ".fbx", Factory::BuildMesh);
LoadResources("data\\lights\\", ".lit", Factory::BuildLight);


At first I thought it would work due to the inheritance, but
it wont work because the function signatures don't match.
BuildShape() returns a Shape*
function pointer returns a Component*

I could make all the Factory::Build functions return Component*, doesn't really make sense though does it? When I call BuildShape(), I would expect it to return the entire Shape, not just the component part.

Any solutions or alternatives would be appreciated.
First: Yes BuildShape and following can return Component*. It does return the entire Shape. Returning a pointer to the base class doesn't mean that the inherited class will vanish.

With dynamic_cast<Shape *>(pointer to Component) you can later access that class.

dynamic_cast returns a pointer that is different from NULL only when the class is indeed a Shape

Second: Make those Build... function static if possible. Passing a pointer to a member function is much more difficult
The following are equivalent
1
2
Shape* const Factory::BuildShape(std::string _file);
Shape* const BuildShape(Factory &self, std::string _file);

So you are not respecting the prototype Component* (*BuildComponent)(std::string)
You can make all the functions return Component* but avoid at all costs dynamic_cast. It's a sign of bad desing and can be avoided with proper use of virtual functions.

I suggest you to learn more about inheritence and polymorphism before coding your engine as you don't seems very confident with it.
As suggested by coder777, I have made my build functions static.
I have turned the LoadResources function into a templated function.
1
2
3
4
5
6
class Factory
{
  public:  static Shape* BuildShape(std::string _file);
           static Mesh* BuildMesh(std::string _file);
           static Light* BuildLight(std::string _file);
};


1
2
3
4
5
6
7
8
class Graphics
{
  private:  GFXlib gfx_;  //directX9 wrapper
            template<typename T>
            void LoadResources(std::string _dir, std::string _ext,
                               T* (*BuildComponent)(std::string));
  public:   void Initialize();
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Graphics::Initialize()
{
  LoadResources<Shape>("\\data\\shapes\\", ".shp", Factory::BuildShape);
  LoadResources<Mesh>("\\data\\meshes\\", ".fbx", Factory::BuildMesh);
  LoadResources<Light>("\\data\\lights\\", ".lit", Factory::BuildLight);
}

template<typename T>
void Graphics::LoadComponents(std::string _dir, std::string _ext,
			      T* (*BuildComponent)(std::string))
{
  std::vector<std::string> fileList;
  GetFiles(_dir, _ext, &fileList);  //get file names in directory with extension
  for(unsigned int i = 0; i < fileList.size(); ++i)
  {
    T* com = BuildComponent(fileList[i]); //build component using file
    gfx_.RegisterComponent(com);  //register component with video device
  }
}


1
2
3
4
5
6
class GFXlib
{
  public:  void RegisterComponent(Shape* _shape);
              void RegisterComponent(Mesh* _mesh);
              void RegisterComponent(Light* _light);
};


If there are any issues with this change please let me know. Thanks.
Topic archived. No new replies allowed.