Question

Having in mind the abstract factory pattern, imagine that you have a class hierarchy where concrete factories override a createButton*s* virtual method, needing to return a wider array of buttons. What could be an elegant workaround to resolve this, as C++ supports only covariant return types? dynamic_cast?

A modified version of GoF's example to fit my requirement:

class Button {
public:
        virtual void paint() = 0;
        virtual ~Button(){
        }
};

class WinButton: public Button {
public:
        void paint() {
                cout << "I'm a WinButton";
        }
};

class OSXButton: public Button {
public:
        void paint() {
                cout << "I'm an OSXButton";
        }
};

class GUIFactory {
public:
        virtual Button * createButtons() = 0;
        virtual ~GUIFactory(){
        }
};

class WinFactory: public GUIFactory {
public:
        WinButton* createButtons() {
                return new WinButton[2];
        }

        ~WinFactory(){
        }
};

class OSXFactory: public GUIFactory {
public:
        OSXButton* createButtons() {
                return new OSXButton[2];
        }

        ~OSXFactory(){
        }
};

And the application skeleton:

Application(GUIFactory * factory) {
                Button* buttons = factory->createButtons();
                for(...) {...}
        }
Was it helpful?

Solution

It cannot be done. Ask yourself, will the caller delete or delete[] it? How will they know how many elements are in the arrays? There's no way to solve either of these problems with a raw pointer return. So the simple answer to your question is that this cannot be done, nor should you even want to. The callee needs to know the return type- whether it's one button or many, and how to clean them up when he's done.

You can't even access the non-first element without invoking Undefined Behaviour.

A Factory is supposed to construct individual objects. If you need more than one, call the factory function more than once.

Even if you magically had code that could deal with more than one button at once when they were expecting just one (wtf?), you need to safely return more than one. That means std::vector<smart_pointer<Button>>.

OTHER TIPS

You do not want to create an array in the factory method and return a pointer to the client. That way you have no idea how many buttons there are, so you really cannot do anything with what you get.

In C++11 you can return a std::vector<shared_ptr<Button>> or even a std::vector<unique_ptr<Button>>.

I would probably opt for this solution though: Return some sort of a custom "readonly" Button collection that exposes the count and an indexer and nothing more. Maybe add iterators, if that'd suit your scenarios.

class ButtonCollection
{
public:
    size_t getCount() const {}
    Button& getAt(size_t index) {}
    const Button& getAt(size_t index) const {}

private:
    friend class GUIFactory;

    ButtonCollection() {}
    add(Button* button) {}
    // Or in C++11:
    // add(std::unique_ptr<Button> button) {}
};

With your application skeleton:

Application(GUIFactory& factory)
{
   std::auto_ptr<ButtonCollection> buttons = factory.createButtons();
   // Or in C++11:
   //std::unique_ptr<ButtonCollection> buttons = factory.createButtons();
   for(...) {...}
}

Consider using boost::ptr_vector or boost::ptr_array
http://www.boost.org/doc/libs/1_48_0/libs/ptr_container/doc/ptr_vector.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top