Search code examples
c++polymorphismstdmap

C++ map of polymorphic functions


I want to use a C++ map of function to execute some subroutines. Since, such a map of function requires to have the same type of input and output for all the mapped functions, while my functions can have different input type, I though I could made all these different types derive from a SuperParentClass.

However, this idea gives me some troubles. It does not compile. Indeed, the compiler capture the derived type and not the parent class. But if you I directly the parent class in my functions, I won't be able to use their specialties inside my functions (so I come for help).

Here is my MWE:

#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <math.h> 


class SuperParentClass
{
private:
    /* data */
public:
    std::string nameClass;
};

class ChildClassRectangle : public SuperParentClass
{
private:
    /* data */
public:
    int longueur=2;
    int largeur=2;
};

class ChildClassCircle : public SuperParentClass
{
private:
    /* data */
public:
    int radius=2;
};

int areaRect(ChildClassRectangle rect)
{
    std::cout << "areaRect "<< rect.largeur*rect.longueur << std::endl;
    return 0;
}

int areaCircle(ChildClassCircle circ)
{
    std::cout << "areaCircle "<< 3.14*pow(circ.radius,2) << std::endl;
    return 0;
}


int main()
{  
    std::cout << "TEST " << std::endl;
    std::map<std::string, SuperParentClass> mapObject;
    ChildClassCircle circ;
    circ.radius=2;
    mapObject["Circle"]=circ;
    ChildClassRectangle rect;
    rect.longueur=1;
    rect.largeur=3;
    mapObject["Rectangle"]=rect;
    
    using CallFunc = std::function<int(SuperParentClass)>;
    std::map<std::string, CallFunc> mapFunction;
    // mapFunction["Circle"]=areaCircle;
    // mapFunction["Rectangle"]=areaRect;

    // mapFunction["Circle"](mapObject["Circle"]);
    // mapObject["Rectangle"].largeur=4;
    // mapFunction["Rectangle"](mapObject["Rectangle"]);
};

The last 5 lines are commented are what I want to do that is not working.


Solution

  • Rather than having a map go to functions it can map to a SuperParentClass pointer. Then use a virtual function in each class to encapsulate the desired behavior.

    
    int areaRect(ChildClassRectangle rect);
    int areaCircle(ChildClassCircle circ);
    
    class SuperParentClass
    {
    public:
        virtual int area() = 0;
        ... // more code...
    };
    
    class ChildClassRectangle : public SuperParentClass
    {
    public:
        virtual int area() override
        {
            return areaRect(*this);
        }
        ... // more code...
    };
    
    class ChildClassCircle : public SuperParentClass
    {
    public:
        virtual int area() override
        {
            return areaCircle(*this);
        }
        ... // more code...
    };
    

    To eliminate the pass by value of classes, simply move the functions into the area() functions.

    Now function calls are directly available without a separate map.

    Here is a rough version that probably doesn't work exactly; but conveys the idea.

    void main()
    {
        std::map<std::string, SuperParentClass*> mapObject;
        ...
        mapObject["Circle"]=&circ;
        ...
        mapObject["Rectangle"]=&rect;
    
        ...
        const int circleReturn = mapObject["Circle"]->area();
        // Cannot access derived properties here
        // mapObject["Rectangle"]->largeur=4; // No longer valid.
        const int rectReturn = mapObject["Rectangle"]->area();
    }
    
    

    Pointers aren't required here; as objects can be emplaced on the container; or some other type of data structuring. This is simply meant to show using a virtual function is a simpler approach and better design.