Search code examples
c++scopepolymorphismfactoryencapsulation

Accessing members of a derived class from a factory created instance


I have a simple Shape factory example where I can create Circles or Squares.

I have added an extra "contents" attribute to the Circle class that is not part of the Square derived class or the Shape base class.

The problem is, when I create an instance of the Circle class using my factory, I am unable to modify the contents of the created object.

#include <iostream>

using namespace std;

// Shape base clas
class Shape {
public:

    // Shape constructor;
    Shape() {
        id_ = total_++;
    }

    // Virtual draw method
    virtual void draw() = 0;

protected:

    int id_;
    static int total_;
};
int Shape::total_ = 0;

// Circle derived class
class Circle : public Shape {
public:
    void draw() {
        contents = 0;
        cout << "circle " << id_ << ": draw, contents: " << contents << endl;
    }

    // Attribute to attempt to access
    int contents;
};

// Square derived class
class Square : public Shape {
public:
    void draw() {
        cout << "square " << id_ << ": draw" << endl;
    }
};

// Factory class
class Factory {
public:
    Shape* createCurvedInstance() {
        return new Circle;
    }
    Shape* createStraightInstance() {
        return new Square;
    }
};

// Main
int main()
{
    Factory* factory = new Factory;
    Shape* thing = factory->createCurvedInstance();

    // Draw method works fine (as it should)
    thing->draw();

    // Fails: "expression must have class type"
    thing.contents = 4;

    system("pause");

    return 0;
}

How can I access attributes of the derived class when I create an instance of it using a factory?


Solution

  • It turns out I didn't want a factory at all!

    What I really wanted was some sort of container class to hold different types of shapes. Neither shape is derived from the ShapeContainer class but both shapes can be accessed through it.

    #include <iostream>
    
    using namespace std;
    
    // Circle class
    class Circle {
    public:
        Circle() {
            contents = 2;
        }
        void draw() {
            cout << "circle " << contents << endl;
        }
    
        int contents;
    };
    
    // Square class
    class Square {
    public:
        void draw() {
            cout << "square" << endl;
        }
    };
    
    // Shape containter class
    class ShapeContainer {
    public:
        Circle* getCircle() {
            return new Circle;
        }
        Square* getSquare() {
            return new Square;  
        };
    };
    
    // Main
    int main()
    {
        ShapeContainer* container = new ShapeContainer;
        Circle* circle = container->getCircle();
    
        circle->draw();
        circle->contents = 42;
        circle->draw();
    
        system("pause");
        return 0;
    }
    

    This allows me to make both Circles and Squares while still being able to access the contents of the Circle object!

    Sometimes you need to look at things from a whole new perspective to get the functionality you really want...