PDA

View Full Version : Inheritance of a static object factory



nomiz
8th March 2012, 19:41
Dear all,

Could someone please explain what I am doing wrong below, and why this is not working?

Thanks!

In a dynamic library i have a class LibObject that has a static function createObject() which returns an instance of itself:


class LibObject
{
private:
int a;

public:
LibObject();
static LibObject createObject(); // the LibObject factory
int getA();
void setA(int i);
}

LibOjcect::LibObject() {}

LibObject LibObject::createObject() { // the LibObject factory
LibObject o;
return o;
}

int LibObject::getA() { return a }

void LibObject::setA(int i) { a = i }

Now in another class Object I am extending the LibObjectclass:


class Object : public LibObject
{
public:
Object();
}

Object::Object() {}

Ok. So, now a third class would like to add Object objects to a QList:


class Test
{
private:
QList<Object> objects;

public:
Test();
}

Test::Test()
{
objects.append(Object::createObject());
}

At compile time I get this error:
error: no matching function for call to 'QList<Object>::append(LibObject)'

So, is the static function createObject() not copied to the Object declaration?

wayfaerer
8th March 2012, 19:58
Shouldn't that be "QList<LibObject>" in class Test?

nomiz
8th March 2012, 20:01
Well, I would like it to be QList<Object>, because I want to add stuff in Object relative to LibObject..

wayfaerer
8th March 2012, 20:07
But LibObject::createObject() returns a LibObject, not an Object. You can make it return an Object if you want it to.

nomiz
8th March 2012, 20:16
Please explain. Do I have to re-declare the createObject() method in the Object class definition?

wayfaerer
8th March 2012, 20:22
I don't think so.

A base class factory method can (and often does) return an instance of a derived class. You would just change LibObject::createObject to:


Object LibObject::createObject() {
Object o;
return o;
}

There's an excellent example of something similar here (in the "after" section): http://sourcemaking.com/design_patterns/factory_method/cpp/1

nomiz
8th March 2012, 20:26
No way! But then, shouldn't LibObject (the base class) be aware of its subclass (Object)? I think I don't exactly understand it yet, but I'll read your reference. Thanks!

wayfaerer
8th March 2012, 20:35
It blew my mind too. :)

It should be aware of the subclass, in the sense that it needs to #include the subclass's header file (or they could be in the same header file).

nomiz
8th March 2012, 21:30
Cool! I'l try :)

Added after 14 minutes:

Hmm, the LibObstacle class cannot access class Object, because LibObject is a class in a shared library. And class Object resides in another application. What now??

Added after 27 minutes:

Maybe I should forget about using the static factory function? I could add a LibObject::setAllAttributes() function and in Test use something like


Test::Test()
{
Object o;
o.setAllAttributes();
objects.append(o);
}


Added after 9 minutes:

Ok, that works. But it is not very elegant. What could be a better solution, still using the factory-pattern?

ChrisW67
8th March 2012, 22:21
You are storing actual instances in the list: LibObject and Object are not interchangable. Pointers to LibObjects and Objects could both be stored in a QList<LibObject*> because a base class pointer can point to an instance of a derived class:


#include <QtCore>
#include <QDebug>

class LibObject {
public:
virtual void saySomething() { qDebug() << "LibObject"; }
};

class ObjectA: public LibObject {
public:
virtual void saySomething() { qDebug() << "ObjectA"; }
};

class ObjectB: public LibObject {
public:
virtual void saySomething() { qDebug() << "ObjectB"; }
};

class ObjectC: public LibObject {
public:
virtual void saySomething() { qDebug() << "ObjectC"; }
};

// The factory method needs to know about all the classes but returns a pointer to the base class
LibObject *createObject(int type)
{
switch(type) {
case 0: return new ObjectA;
case 1: return new ObjectB;
case 2: return new ObjectC;
}
return 0;
}

int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);

// only need to know that a LibObject class exists to do this
QList<LibObject *> list;
list << createObject(0) << createObject(1) << createObject(2);
foreach(LibObject *o, list)
o->saySomething();
qDeleteAll(list);

return 0;
}

nomiz
10th March 2012, 14:22
Alright. Thanks for the explanation Chris!