Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching an overloaded function to its polymorphic argument

Okay, the title is a mouthful and I think that's probably why it has been tough to find an answer through google or this site. It might just be that I don't know how to express the problem correctly but here goes:

I have a series of methods in a SimpleOpenGLRenderer class that all take a single argument that extends the Model class. So the idea is that depending on the type of model, the renderer will invoke the correct method that knows how to render it. Here is a simplified executable example based on the problem:

#include <stdio.h>

class Model {};

class Cube : public Model {};

class Sphere : public Model {};

class Renderer
{
  public:
    virtual void renderModel(const Model& model) = 0;
};

class SimpleOpenGLRenderer
{
  public:
    void renderModel(const Cube& model)
    {
      printf("Render the cube.\n");
    }

    void renderModel(const Model& model)
    {
      printf("Throw an exception, my renderer does not support the model type you have provided.\n");
    }

    void renderModel(const Sphere& model)
    {
      printf("Render the sphere.\n");
    }
};

int
main(int argc, char** argv)
{
  Cube cube;
  Model& model = cube;
  SimpleOpenGLRenderer renderer;

  renderer.renderModel(cube);
  renderer.renderModel(model);
}

The output from the example is:

Render the cube.
Throw an exception, my renderer does not support the model type you have provided.

It may seem obvious to a more seasoned C++ developer that this does not work as planned but it just doesn't make sense to me. At runtime I will not know the exact type of the Model passed to the renderer (hence the attempted overloading to resolve it). Coming from a Java background, I have used this technique before and in Java the method called will be that which best matches the runtime type of the argument. In C++ it seems to match to the compile-time type of the reference, even if that reference may end up being to a subclass that - to my mind - better matches another function.

Up until now I had taken this runtime type matching for granted. Does it simply not exist in C++ or am I going about this the wrong way? Should I be doing something differently in C++ to achieve it?

Thanks,

Gary.

like image 476
Gyan aka Gary Buyn Avatar asked Aug 01 '11 11:08

Gyan aka Gary Buyn


People also ask

What is the relation between polymorphism and function overloading?

Polymorphism in Function Overloading In computing, polymorphism is a property of object oriented programming in which a function can take different forms based on the number of arguments and their data types. All the functions will have the same name, but they will differ in their arguments.

How function overloading is application of polymorphism?

Function overloading means one function can perform many tasks. In C++, a single function is used to perform many tasks with the same name and different types of arguments. In the function overloading function will call at the time of program compilation. It is an example of compile-time polymorphism.

How are function calls matched with overloaded functions?

The compiler selects which overloaded function to invoke based on the best match among the function declarations in the current scope to the arguments supplied in the function call. If a suitable function is found, that function is called. "Suitable" in this context means either: An exact match was found.

When function is overloaded which part of the function are the same?

Function overloading is a feature that allows us to have same function more than once in a program. Overloaded functions have same name but their signature must be different.


2 Answers

Overloads in C++ are resolved at compile time, based on the static type of the argument.

There's a technique known as "double-dispatch" that might be of use:

class Model {
    virtual void dispatchRender(Renderer &r) const = 0;
};

class Cube : public Model {
    virtual void dispatchRender(Renderer &r) const {
        r.renderModel(*this); // type of "this" is const Cube*
};

int main() {
    Cube cube;
    Model &model = cube;
    SimpleOpenGLRenderer renderer;
    cube.dispatchRender(renderer);
}

Note that the Renderer base class needs to contain all the overloads that SimpleOpenGLRenderer currently does. If you want it to be specific to SimpleOpenGLRenderer what overloads exist then you could put a Simple-specific dispatch function in Model, or you could ignore this technique and instead use dynamic_cast repeatedly in SimpleOpenGLRenderer::renderModel to test the type.

like image 155
Steve Jessop Avatar answered Oct 25 '22 23:10

Steve Jessop


In your code, the function overloads are resolved based on the static type of the argument.

What you need probably is double-dispatch mechanism which is very close to Visitor pattern. Read these:

  • Double Dispatch
  • Visitor Pattern
like image 28
Nawaz Avatar answered Oct 26 '22 01:10

Nawaz