Hello,

I am working on an event driven library and am having one minor problem. Basically I have two ways to get what I want done.

Method 1: Smart pointers and factory functions

#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Object
{
    public:
    virtual int getInt(){return 0;}
    static shared_ptr<Object> create()
    {// of course this could be replaced with the templated version to make it work for any constructor
        return shared_ptr<Object>(new Object());
    }
};
class One:public Object
{
    public:
    virtual int getInt(){return 1;}
    static shared_ptr<One> create()
    {
        return shared_ptr<One>(new One());
    }
};
class Incrementer:public Object
{
    int x;
    public:
    Incrementer():x(0){}
    Incrementer(int i):x(i){}
    virtual int getInt(){return x++;}
    static shared_ptr<Incrementer> create()
    {
        return shared_ptr<Incrementer>(new Incrementer());
    }
};
class Scene
{
    vector<shared_ptr<Object> > os;
    public:
    Scene &add(shared_ptr<Object> o)
    {
        os.push_back(o);
        return *this;
    }
    Scene &print(){
        for (size_t i=0; i<os.size(); ++i)
            cout<<os[i]->getInt()<<endl;
        return *this;
    }
};
int main() {
    Scene s;
    s.add(One::create());
    s.add(Incrementer::create());
    s.print().print().print();
    return 0;
}

Method 2: Clone function

#include <iostream>
#include <vector>
using namespace std;
class Object
{
    public:
    virtual int getInt(){return 0;}
    virtual Object* clone(){return new Object;}
};
class One:public Object
{
    public:
    virtual int getInt(){return 1;}
    virtual One* clone(){return new One;}
};
class Incrementer:public Object
{
    int x;
    public:
    Incrementer():x(0){}
    Incrementer(int i):x(i){}
    virtual int getInt(){return x++;}
    virtual Incrementer* clone(){return new Incrementer(x);}
};
class Scene
{
    vector<Object *> os;
    public:
    Scene &add(Object *o)
    {
        os.push_back(o->clone());
    }
    Scene &print(){
        for (size_t i=0; i<os.size(); ++i)
            cout<<os[i]->getInt()<<endl;
        return *this;
    }
    ~Scene()
    {
        for (size_t i=0; i<os.size(); ++i)
            delete os[i];
    }
};
int main() {
    Scene s;
    Incrementer i;
    {
        One *one=new One;
        s.add(one);
        delete one;
    }
    s.add(&i);
    s.print().print().print();
    return 0;
}

I tend to prefer method 1 (it looks cleaner, and is less prone to error) however both have a problem in that they both require that the user add a function to every class that they wish to use. If they forget to write a create() or clone() function then the library would fail. Is it possible to achieve this kind of functionality without forcing the user to add a specific function to each class?

Well, first of all, the two options are not mutually exclusive, there is not problem with providing both a factory function (create) and a polymorphic cloning function, it is, in fact, very common. Something like this:

class Object {
  public:
    // NEVER FORGET THE VIRTUAL DESTRUCTOR!!!
    virtual ~Object() { };

    virtual int getInt() { return 0; };

    virtual unique_ptr<Object> clone() const {
      return unique_ptr<Object>(new Object(*this));
    };

    template <typename... Args>
    static unique_ptr<Object> create(Args&&... args) {
      return unique_ptr<Object>(new Object(std::forward<Args>(args)...));
    };
};


class One : public Object {
  public:

    virtual int getInt(){return 1;}

    virtual unique_ptr<Object> clone() const {
      return unique_ptr<Object>(new One(*this));
    };

    template <typename... Args>
    static unique_ptr<One> create(Args&&... args) {
      return unique_ptr<One>(new One(std::forward<Args>(args)...));
    };
};

The use of the unique_ptr in the factory function is just because they are implicitely moveable into a shared_ptr, so, there is no reason to "commit yourself" to the shared_ptr in the factory function. Instead, let the calling context determine if the caller of the factory function wants to put the result in a shared-pointer or in a unique-pointer. But if you want to avoid using unique-pointers (since they are C++11 only, as opposed to shared-pointers which exist since TR1 and are available in Boost), then using shared_ptr is also perfectly acceptable.

Is it possible to achieve this kind of functionality without forcing the user to add a specific function to each class?

This is a bit difficult. As far as I know, there is no clever trick to achieve this in a really nice way. I have similar things in my library, and there are many other libraries that face the same kind of problem (e.g., Qt). It seems that the only solution is to use a MACRO. For example, here is a possible MACRO to use:

#define MY_LIBRARY_MAKE_CREATE_AND_CLONE(CLASSNAME, BASECLASS) \
  public: \
    virtual std::unique_ptr<BASECLASS> clone() const { \
      return std::unique_ptr<BASECLASS>(new CLASSNAME(*this)); \
    }; \
     \
    template <typename... Args> \
    static std::unique_ptr<CLASSNAME> create(Args&&... args) { \
      return std::unique_ptr<CLASSNAME>(new CLASSNAME(std::forward<Args>(args)...)); \
    };

which you would then add to your classes as follows:

class Object {
  public:
    // NEVER FORGET THE VIRTUAL DESTRUCTOR!!!
    virtual ~Object() { };

    virtual int getInt() { return 0; };

  MY_LIBRARY_MAKE_CREATE_AND_CLONE(Object,Object)
};

class One : public Object {
  public:

    virtual int getInt(){return 1;}

  MY_LIBRARY_MAKE_CREATE_AND_CLONE(One,Object)
};

There are many libraries that use this scheme. You have to be careful with the placement of the MACRO in the class definition. Obviously, you cannot just put it anywhere because it leaves a trail (it changes the access rights to "public", so, if you place it in a private section, you'll end up in making it a public section after the MACRO). Usually, placing the MACRO at the very end of the class declaration (just before the closing curly-brace) is going to work fine. This is one of the few places where MACROs are kind of necessary, because there is no neat way to make this work in "normal code".

Having used this pattern (with the macro cruft) much in the past, I can say that it is very efficacious, but it is not easy when debugging... :-) However, I give Mike2k a thumbs up for suggesting it.

but it is not easy when debugging... :-)

Yeah, that's true, that's one of the annoying things with MACROs. However, you should try using the Clang compiler instead of GCC (or others..) because it has great diagnostics of compilation errors, including the expansion of MACROs to show where the error actually occurs in the post-MACRO-expanded version of the code. Much nicer.

But all in all, any code that you are going to put in this kind of MACRO should be very heavily tested before to make sure it doesn't have any serious problems or bad interactions with the rest of the code.

And, AFAIK, for this kind of problem the only real alternative is to do like Qt has done with their "QT_OBJECT" thing, that is, have their own pre-processor program to go an insert all those bits of "ground-work" code. But, I think that sticking with the standard pre-processor and regular MACROs is better for as long as it's sufficient.

Ok, thanks. I was thinking maybe there existed a way to duplicate the block in memory where the class is stored and use that, but I guess that would require a sizeof(Base*)<==>sizeof(Derived) situation which isn't really possible.

PS: I have GOT to start remembering my virtual destructors >< thanks for the reminders!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.