c++oophierarchydouble-dispatch

Double dispatch and factory pattern


I've got the following code currently (not working):

#include <iostream>
#include <vector>

class Circle;
class Rectangle;

class Shape {
private:
    Shape() {};
public:
    virtual ~Shape() {};
    friend class Circle;
    friend class Rectangle;
};

class Creator {
public:
    virtual ~Creator() {};
    virtual Shape* create() = 0;
    virtual bool equals(Shape& s) { return false; };
};

class Circle : public Shape {
private:
    Circle() : Shape() {};
public:
    class CircleCreator : public Creator {
    public:
        virtual Shape* create() { return new Circle(); };
        virtual bool equals(Shape& other_shape) { return false; };
    };
};

class Rectangle : public Shape {
private:
    Rectangle() : Shape() {};
public:
    class RectangleCreator : public Creator {
    public:
        virtual Shape* create() { return new Rectangle(); };
        virtual bool equals(Shape& other_shape) { return false; };
    };
};

int main() {
    /* First step, build the list */
    std::vector<Shape*> shapeList;
    std::vector<Shape*>::iterator it;
    Rectangle::RectangleCreator rc;
    Circle::CircleCreator cc;
    Shape* s = cc.create();
    Shape* s1 = rc.create();
    shapeList.push_back(s);
    shapeList.push_back(s1);

    /* Second step: check if we've got a shape starting from a creator */
    for (it = shapeList.begin(); it != shapeList.end(); ++it) {
        if (rc.equals(**it)) {
            std::cout << "same shape" << std::endl;
        }
    }
    return 0;
}

My goal is to use a factory pattern and avoid the creation of a new object if in a list I've got already that object. I tried to use a double dispatch pattern but it isn't easy to apply in this case. How can I do?

Edit: Since the code is used in a "critical" path, I want to avoid RTTI like dynamic_cast and so on.


Solution

  • Maybe something like this could do it using member variables

    #include <iostream>
    #include <vector>
    
    enum
    {
    CIRCLE,
    RECTANGLE
    };
    
    class Circle;
    class Rectangle;
    
    class Shape {
    private:
        Shape() {};
    public:
        unsigned shapeType;
        virtual ~Shape() {};
        friend class Circle;
        friend class Rectangle;
    };
    
    class Creator {
    public:
    unsigned shapeType;
        virtual ~Creator() {};
        virtual Shape* create() = 0;
        bool equals(Shape& s) { return (this->shapeType == s.shapeType); };
    };
    
    class Circle : public Shape {
    private:
        Circle() : Shape() {shapeType=CIRCLE;};
    public:
        class CircleCreator : public Creator {
        public:
            CircleCreator() {shapeType=CIRCLE;};
            virtual Shape* create() { return new Circle(); };
        };
    };
    
    class Rectangle : public Shape {
    private:
        Rectangle() : Shape() {shapeType=RECTANGLE;};
    public:
        class RectangleCreator : public Creator {
        public:
            RectangleCreator() {shapeType=RECTANGLE;};
            virtual Shape* create() { return new Rectangle(); };
        };
    };
    
    int main() {
        /* First step, build the list */
        std::vector<Shape*> shapeList;
        std::vector<Shape*>::iterator it;
        Rectangle::RectangleCreator rc;
        Circle::CircleCreator cc;
        Shape* s = cc.create();
        Shape* s1 = rc.create();
        shapeList.push_back(s);
        shapeList.push_back(s1);
    
        /* Second step: check if we've got a shape starting from a creator */
        for (it = shapeList.begin(); it != shapeList.end(); ++it) {
            if (rc.equals(**it)) {
                std::cout << "same shape" << std::endl;
            }
        }
        return 0;
    }
    

    or this - using virtual function to return type

    #include <iostream>
    #include <vector>
    
    enum
    {
        CIRCLE,
    RECTANGLE,
    UNKNOWN
    };
    class Circle;
    class Rectangle;
    
    class Shape {
    private:
        Shape() {};
    public:
        virtual ~Shape() {};
        friend class Circle;
        friend class Rectangle;
        virtual unsigned iAmA(){return UNKNOWN;};
    };
    
    class Creator {
    public:
        virtual ~Creator() {};
        virtual Shape* create() = 0;
        virtual bool equals(Shape& s) { return false; };
    };
    
    class Circle : public Shape {
    private:
        Circle() : Shape() {};
        virtual unsigned iAmA(){return CIRCLE;};
    public:
        class CircleCreator : public Creator {
        public:
            CircleCreator() {};
            virtual Shape* create() { return new Circle(); };
            virtual bool equals(Shape& other_shape) { return (CIRCLE == other_shape.iAmA()); };
        };
    };
    
    class Rectangle : public Shape {
    private:
        Rectangle() : Shape() {};
        virtual unsigned iAmA(){return RECTANGLE;};
    public:
        class RectangleCreator : public Creator {
        public:
            RectangleCreator() {};
            virtual Shape* create() { return new Rectangle(); };
            virtual bool equals(Shape& other_shape) { return (RECTANGLE == other_shape.iAmA()); };
        };
    };
    
    int main() {
        /* First step, build the list */
        std::vector<Shape*> shapeList;
        std::vector<Shape*>::iterator it;
        Rectangle::RectangleCreator rc;
        Circle::CircleCreator cc;
        Shape* s = cc.create();
        Shape* s1 = rc.create();
        shapeList.push_back(s);
        shapeList.push_back(s1);
    
        /* Second step: check if we've got a shape starting from a creator */
        for (it = shapeList.begin(); it != shapeList.end(); ++it) {
            if (rc.equals(**it)) {
                std::cout << "same shape" << std::endl;
            }
        }
        return 0;
    }