By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,436 Members | 1,363 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,436 IT Pros & Developers. It's quick & easy.

Choosing a class using a variable without if-else

P: n/a
Hi,

As part of a simulation program, I have several different model
classes, ModelAA, ModelBB, etc., which are all derived from the class
BasicModel by inheritance.
>From a command-line parameter, I need to choose the correct type of
model to use, for example if the parameter model_name is "aa", then
choose ModelAA.

Currently I do this as follows:

BasicModel* model;

if (model_name == "aa") {
model = new ModelAA(a,b,c);
}

else if (model_name == "bb") {
model = new ModelBB(a,b,c);
}

etc., through all the (many) models.
Each model constructor takes the same parameters, if this is of any
help.

Once this is done, only virtual functions in BasicModel are called.
(But the implementation of these can be very different in the different
kinds of model.)

It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).

I have looked hard at the FAQ, and I cannot see anything that is
relevant (but please correct me if I'm wrong). Any suggestions or
pointers would be greatly appreciated.

Thanks and best wishes,
David.

Dec 23 '06 #1
Share this Question
Share on Google+
25 Replies


P: n/a

David Sanders wrote:
It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).
#include <map>
#include <string>
#include <iostream>

struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;
};

struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}
};

struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}
};

BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);
}

BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);
}

typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
model_map_type;
int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;

BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';

BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';
}

Dec 23 '06 #2

P: n/a
David Sanders wrote:
As part of a simulation program, I have several different model
classes, ModelAA, ModelBB, etc., which are all derived from the class
BasicModel by inheritance.

From a command-line parameter, I need to choose the correct type of
model to use, for example if the parameter model_name is "aa", then
choose ModelAA.

Currently I do this as follows:

BasicModel* model;

if (model_name == "aa") {
model = new ModelAA(a,b,c);
}

else if (model_name == "bb") {
model = new ModelBB(a,b,c);
}

etc., through all the (many) models.
Each model constructor takes the same parameters, if this is of any
help.
I would suggest implementing a "registration" model, in which each
BasicModel subclass has to register its name and its static creation
routine in a central map. The routine that creates BasicModel subclass
objects by name would consult this central map in order to match the
class name with the appropriate creation routine that had been
registered. If a routine is found, then it is invoked to create an
object of the requested type.

To enforce registration, each BasicModel subclass would inherit from a
"ClassMap" template with the template's type parameter being the
BasicModel subclass itself. Each BasicModel subclass would also have to
implement two static routines (or it would not compile): a GetName()
routine (returning the name used to create an object of that class) and
a static Create() routine that allocates an object of the matching
class.

Here is a basic implementation of the preceding ideas in case you would
like to experiment with any of them:

#include <iostream>
#include <map>
#include <string>

using std::map;
using std::string;

class BasicModel;

typedef map<string, BasicModel* (*)()ClassNameMap;

struct ClassMapBase
{
static ClassNameMap sClassMap;
};

template <class T>
struct ClassMap : public ClassMapBase
{
ClassMap(const string& name = std::string(""))
{
if (name.length())
{
std::cout << "Registering: " << T::GetName() << "\n";

sInstance.sClassMap[ T::GetName()] = T::Create;
}
}
static ClassMap sInstance;
};

class BasicModel
{
public:
BasicModel() {}

static
BasicModel* CreateByName( const string& name)
{
ClassNameMap::iterator iter;

iter = ClassMapBase::sClassMap.find( name );

if (iter != ClassMapBase::sClassMap.end())
{
return (*iter).second();
}
return NULL;
}
};

// ModelAA inherits from ClassMap thereby registering itself

class ModelAA : public BasicModel, ClassMap<ModelAA>
{
public:
ModelAA() : BasicModel() {}

// required GetName() routine

static string GetName()
{
return "aa";
}

// required Create() routine

static BasicModel * Create()
{
return new ModelAA;
}
};

// some class static variables

ClassNameMap ClassMapBase::sClassMap;

// the self-registering static variable

template <class T>
ClassMap<TClassMap<T>::sInstance( T::GetName() );

int main()
{
BasicModel * a = BasicModel::CreateByName("aa");

// a is a ModelAA *
}

Program Output:

Registering: aa

Greg

Dec 23 '06 #3

P: n/a


On Dec 23, 9:51 am, "Greg" <gre...@pacbell.netwrote:
David Sanders wrote:
As part of a simulation program, I have several different model
classes, ModelAA, ModelBB, etc., which are all derived from the class
BasicModel by inheritance.
From a command-line parameter, I need to choose the correct type of
model to use, for example if the parameter model_name is "aa", then
choose ModelAA.
Currently I do this as follows:
BasicModel* model;
if (model_name == "aa") {
model = new ModelAA(a,b,c);
}
else if (model_name == "bb") {
model = new ModelBB(a,b,c);
}
etc., through all the (many) models.
Each model constructor takes the same parameters, if this is of any
help.I would suggest implementing a "registration" model, in which each
BasicModel subclass has to register its name and its static creation
routine in a central map. The routine that creates BasicModel subclass
objects by name would consult this central map in order to match the
class name with the appropriate creation routine that had been
registered. If a routine is found, then it is invoked to create an
object of the requested type.

To enforce registration, each BasicModel subclass would inherit from a
"ClassMap" template with the template's type parameter being the
BasicModel subclass itself. Each BasicModel subclass would also have to
implement two static routines (or it would not compile): a GetName()
routine (returning the name used to create an object of that class) and
a static Create() routine that allocates an object of the matching
class.

Here is a basic implementation of the preceding ideas in case you would
like to experiment with any of them:

#include <iostream>
#include <map>
#include <string>

using std::map;
using std::string;

class BasicModel;

typedef map<string, BasicModel* (*)()ClassNameMap;

struct ClassMapBase
{
static ClassNameMap sClassMap;
};

template <class T>
struct ClassMap : public ClassMapBase
{
ClassMap(const string& name = std::string(""))
{
if (name.length())
{
std::cout << "Registering: " << T::GetName() << "\n";

sInstance.sClassMap[ T::GetName()] = T::Create;
}
}
static ClassMap sInstance;
};

class BasicModel
{
public:
BasicModel() {}

static
BasicModel* CreateByName( const string& name)
{
ClassNameMap::iterator iter;

iter = ClassMapBase::sClassMap.find( name );

if (iter != ClassMapBase::sClassMap.end())
{
return (*iter).second();
}
return NULL;
}
};

// ModelAA inherits from ClassMap thereby registering itself

class ModelAA : public BasicModel, ClassMap<ModelAA>
{
public:
ModelAA() : BasicModel() {}

// required GetName() routine

static string GetName()
{
return "aa";
}

// required Create() routine

static BasicModel * Create()
{
return new ModelAA;
}
};

// some class static variables

ClassNameMap ClassMapBase::sClassMap;

// the self-registering static variable

template <class T>
ClassMap<TClassMap<T>::sInstance( T::GetName() );

int main()
{
BasicModel * a = BasicModel::CreateByName("aa");

// a is a ModelAA *
}

Program Output:

Registering: aa

Greg- Hide quoted text -- Show quoted text -
Nice design, my only input would be that its not usually a good idea to
have base classes know about derived classes - in your case this
knowledge is purely by id and pointer to factory method, instead of a
direct knowledge association.

To finish the design, I would move the CreateByName() method to a
ModelFactory class. This way we keep the ideal of base classes not
knowing about derived classes and more importantly, we have a design
the is compliant with the Single Responsability Principle.

Dec 23 '06 #4

P: n/a


On Dec 23, 7:52 am, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
David Sanders wrote:
It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).#include <map>
#include <string>
#include <iostream>

struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;

};struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}

};struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}

};BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);

}BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);

}typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
model_map_type;int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;

BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';

BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';
The idea is right, but there is currently an implementation problem of
the base class knowing about its derived classes.

This design currently violates the OpenClosed Principle. See my reply
to Greg's message for a slight modification which would solve this.

Andrew

Dec 23 '06 #5

P: n/a

andrewmcdonagh wrote:
On Dec 23, 7:52 am, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
David Sanders wrote:
It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).#include <map>
#include <string>
#include <iostream>

struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;

};struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}

};struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}

};BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);

}BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);

}typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
model_map_type;int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;

BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';

BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';


The idea is right, but there is currently an implementation problem of
the base class knowing about its derived classes.
You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
This design currently violates the OpenClosed Principle. See my reply
to Greg's message for a slight modification which would solve this.
I think you need to provide more details as to how it violates the
OpenClosed principle.

regards
Andy Little

Dec 23 '06 #6

P: n/a


On Dec 23, 12:54 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
andrewmcdonagh wrote:
On Dec 23, 7:52 am, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
David Sanders wrote:
It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).#include <map>
#include <string>
#include <iostream>
struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;
};struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}
};struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}
};BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);
}BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);
}typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
model_map_type;int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;
BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';
BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';
The idea is right, but there is currently an implementation problem of
the base class knowing about its derived classes.You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.
>
This design currently violates the OpenClosed Principle. See my reply
to Greg's message for a slight modification which would solve this.I think you need to provide more details as to how it violates the
OpenClosed principle.

regards
If we want to add a new derived class zz, then we need to
1) Create our new claa ModelZZ
2) modify BasicModel to include knowledge of the new class.
3) Recompile all effected code because BasicModel's interface has
changed

This means BasicModel is not conformant, its not 'Open to extension but
closed to modification'

Take a look at
http://dforge.cse.ucsc.edu/docman/vi...OpenClosed.pdf for more
info....

So, what I was suggesting to Greg, was to move the construction logic
to its own class, making BasicModel changes unneeded.

HTH

Andrew

Dec 23 '06 #7

P: n/a

kwikius wrote:
andrewmcdonagh wrote:
On Dec 23, 7:52 am, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
David Sanders wrote:
It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).#include <map>
#include <string>
#include <iostream>
>
struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;
>
};struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}
>
};struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}
>
};BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);
>
}BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);
>
}typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
>
model_map_type;int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;
>
BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';
>
BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';
>
>
>
The idea is right, but there is currently an implementation problem of
the base class knowing about its derived classes.

You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
This design currently violates the OpenClosed Principle. See my reply
to Greg's message for a slight modification which would solve this.

I think you need to provide more details as to how it violates the
OpenClosed principle.
Many thanks to all for the suggestions. I have some work to do to
understand the answers, but at least I now understand the reason for
design patterns.

Thanks and best wishes,
David.

Dec 23 '06 #8

P: n/a
In article <11**********************@48g2000cwx.googlegroups. com>,
"David Sanders" <dp*******@gmail.comwrote:
Hi,

As part of a simulation program, I have several different model
classes, ModelAA, ModelBB, etc., which are all derived from the class
BasicModel by inheritance.
From a command-line parameter, I need to choose the correct type of
model to use, for example if the parameter model_name is "aa", then
choose ModelAA.

Currently I do this as follows:

BasicModel* model;

if (model_name == "aa") {
model = new ModelAA(a,b,c);
}

else if (model_name == "bb") {
model = new ModelBB(a,b,c);
}

etc., through all the (many) models.
Each model constructor takes the same parameters, if this is of any
help.

Once this is done, only virtual functions in BasicModel are called.
(But the implementation of these can be very different in the different
kinds of model.)

It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).

I have looked hard at the FAQ, and I cannot see anything that is
relevant (but please correct me if I'm wrong). Any suggestions or
pointers would be greatly appreciated.
I think it is important to note that the "extra work" you are trying to
avoid is adding 2 lines in your main every time you make a new
sub-class. That's not much...

In order to save you extra work in this case, the solution must allow
you to add a new class to main with only one line of extra code, and the
number of classes must be great enough to justify the amount of code
required to allow that one line to work.

The best solution I can think of would allow you to add a new class by
doing this:

--- AA.cpp
#include "AA.h"

ModelCreator<AAcreatorAA( "aa" );
--- AA.h
#include "Model.h"

class Aa : public Model
{ };
Thus only one line adds a new model sub-type to main and that one line
can be put in the cpp file of the class. In order for this to work, you
need the following:

--- Model.h
#include <map>
#include <string>

class Model
{
public:
virtual ~Model() { }
};

// support for model creation
class ModelCreatorT {
public:
virtual Model* create() const = 0;
};

std::map< std::string, ModelCreatorT* >& modelMap();

template < typename T >
class ModelCreator : public ModelCreatorT
{
public:
ModelCreator( const char* name ) {
modelMap()[name] = this;
}

Model* create() const {
return new T;
}
};
--- Model.cpp
#include "Model.h"

using namespace std;

map<string, ModelCreatorT*>& modelMap() {
static map<string, ModelCreatorT*models;
return models;
}
--- main.cpp
#include "Model.h"

int main( int argc, char* argv[] )
{
if ( argc 1 )
{
Model* m = modelMap()[argv[1]]->create();
// use m
delete m;
}
}
Now you have to judge if the number of sub-classes of Model is enough to
justify the extra work needed to save you extra work. :-)
Dec 23 '06 #9

P: n/a

andrewmcdonagh wrote:
If we want to add a new derived class zz, then we need to
1) Create our new claa ModelZZ
2) modify BasicModel to include knowledge of the new class.
3) Recompile all effected code because BasicModel's interface has
changed.
No offence but that you are talking complete nonsense.

Here is my code copied from the other post. I've marked the sections
added to create some modelZZ. There has been no mods to the ABC
required to run this

regards
Andy Little

----------------------------------
#include <map>
#include <string>
#include <iostream>

struct BasicModel{
virtual ~BasicModel(){}
// function to identify which it is
virtual const char * sig() const = 0;
};
struct ModelAA : BasicModel{
ModelAA(int a, int b, int c){}
const char * sig() const {return "model aa";}
};
struct ModelBB : BasicModel{
ModelBB(int a, int b, int c){}
const char * sig() const {return "model bb";}
};
BasicModel* make_model_aa(int a, int b, int c)
{
return new ModelAA(a,b,c);
}
BasicModel* make_model_bb(int a, int b, int c)
{
return new ModelBB(a,b,c);
}
typedef std::map<
std::string,
BasicModel* (*)( int,int,int)
model_map_type;

//////////////////// new code //////////

struct ModelZZ : BasicModel{
ModelZZ(int a, int b, int c){}
const char * sig() const {return "model zz";}
};
BasicModel* make_model_zz(int a, int b, int c)
{
return new ModelZZ(a,b,c);
}

////////////// end new code//////////
int main()
{
model_map_type model_maker;
model_maker["aa"]= make_model_aa;
model_maker["bb"]= make_model_bb;

BasicModel * pmaa = model_maker["aa"](1,2,3);
std::cout << pmaa->sig() <<'\n';

BasicModel * pmbb = model_maker["bb"](1,2,3);
std::cout << pmbb->sig() <<'\n';

////////new code //////////////////

model_maker["zz"]= make_model_zz;

BasicModel * pmzz = model_maker["zz"](1,2,3);
std::cout << pmzz->sig() <<'\n';

//////// end new code ////////////////////

}

Dec 23 '06 #10

P: n/a
andrewmcdonagh wrote
kwikius wrote:
andrewmcdonagh wrote:
You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.

Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.
You've still not shown me any proof that my example is incorrect.
You have implied that it is incorrect several times however. Maybe now
you should either prove your point or apologise for making incorrect
statements.
This design currently violates the OpenClosed Principle. See my reply
to Greg's message for a slight modification which would solve this.I think you need to provide more details as to how it violates the
OpenClosed principle.

regards

If we want to add a new derived class zz, then we need to
1) Create our new claa ModelZZ
2) modify BasicModel to include knowledge of the new class.
3) Recompile all effected code because BasicModel's interface has
changed

This means BasicModel is not conformant, its not 'Open to extension but
closed to modification'
That 2nd statement is simply incorrect AFAICS. You need to show me an
example to prove your point.

Take a look at
http://dforge.cse.ucsc.edu/docman/vi...OpenClosed.pdf for more
info....
According to that doc an ABC is a perfectly valid example of
conformance to the so-called open closed principle....
So, what I was suggesting to Greg, was to move the construction logic
to its own class, making BasicModel changes unneeded.

HTH
No I don't think you are helping very much FWIW. Examples please ?

regards
Andy Little

Dec 23 '06 #11

P: n/a

Daniel T. wrote:
In article <11**********************@48g2000cwx.googlegroups. com>,
"David Sanders" <dp*******@gmail.comwrote:
Hi,

As part of a simulation program, I have several different model
classes, ModelAA, ModelBB, etc., which are all derived from the class
BasicModel by inheritance.
>From a command-line parameter, I need to choose the correct type of
model to use, for example if the parameter model_name is "aa", then
choose ModelAA.

Currently I do this as follows:

BasicModel* model;

if (model_name == "aa") {
model = new ModelAA(a,b,c);
}

else if (model_name == "bb") {
model = new ModelBB(a,b,c);
}

etc., through all the (many) models.
Each model constructor takes the same parameters, if this is of any
help.

Once this is done, only virtual functions in BasicModel are called.
(But the implementation of these can be very different in the different
kinds of model.)

It is clear to me that there must be a better way of initiating the
models, which is easier to update when a new model is added, e.g.
involving some kind of array or map, mapping the model_name string to
the class name, but I can't work out the syntax (I am somewhat of a
newbie).

I have looked hard at the FAQ, and I cannot see anything that is
relevant (but please correct me if I'm wrong). Any suggestions or
pointers would be greatly appreciated.

I think it is important to note that the "extra work" you are trying to
avoid is adding 2 lines in your main every time you make a new
sub-class. That's not much...

In order to save you extra work in this case, the solution must allow
you to add a new class to main with only one line of extra code, and the
number of classes must be great enough to justify the amount of code
required to allow that one line to work.

The best solution I can think of would allow you to add a new class by
doing this:

--- AA.cpp
#include "AA.h"

ModelCreator<AAcreatorAA( "aa" );
--- AA.h
#include "Model.h"

class Aa : public Model
{ };
Thus only one line adds a new model sub-type to main and that one line
can be put in the cpp file of the class. In order for this to work, you
need the following:

--- Model.h
#include <map>
#include <string>

class Model
{
public:
virtual ~Model() { }
};

// support for model creation
class ModelCreatorT {
public:
virtual Model* create() const = 0;
};

std::map< std::string, ModelCreatorT* >& modelMap();

template < typename T >
class ModelCreator : public ModelCreatorT
{
public:
ModelCreator( const char* name ) {
modelMap()[name] = this;
}

Model* create() const {
return new T;
}
};
--- Model.cpp
#include "Model.h"

using namespace std;

map<string, ModelCreatorT*>& modelMap() {
static map<string, ModelCreatorT*models;
return models;
}
--- main.cpp
#include "Model.h"

int main( int argc, char* argv[] )
{
if ( argc 1 )
{
Model* m = modelMap()[argv[1]]->create();
// use m
delete m;
}
}
Now you have to judge if the number of sub-classes of Model is enough to
justify the extra work needed to save you extra work. :-)
Hi,
Thanks again to everybody who offered suggestions.
Daniel T.'s comes closest to what I was imagining, although I'm not
surprised I didn't manage it myself -- any of the solutions seem to be
rather complicated and non-intuitive.

I agree that it's not clear that the work saved is worth the extra
work, but I've certainly learnt a lot of nice C++ in the meantime! :-)
Where should I be looking to learn how to write code like this?
(If that's not a silly question.) I am interested in scientific
programming applications, where the same algorithm is applied to
disparate models, and I'm thus interested in learning how to increase
the abstraction level of my code (without sacrificing speed, of
course!)

Thanks and best wishes,
David.

Dec 23 '06 #12

P: n/a
"David Sanders" <dp*******@gmail.comwrote:
Daniel T. wrote:
I think it is important to note that the "extra work" you are
trying to avoid is adding 2 lines in your main every time you make
a new sub-class. That's not much...

In order to save you extra work in this case, the solution must
allow you to add a new class to main with only one line of extra
code, and the number of classes must be great enough to justify
the amount of code required to allow that one line to work.

Thanks again to everybody who offered suggestions. Daniel T.'s comes
closest to what I was imagining, although I'm not surprised I didn't
manage it myself -- any of the solutions seem to be rather
complicated and non-intuitive.
Maybe it seems complicated at first, but after you have seen the
patterns a few times, it gets to be quite simple.

In each class' cpp file, I create a global object. The constructor of
the global objects created log themselves in yet another object (the
"models" object inside the "modelMap()" function.) "main" then accesses
the "models" map and calls create on the appropriate factory.

The only tricky part is making sure that the "models" object is
constructed before any of the factory objects are, that is why the
models object is embedded in a function.
Where should I be looking to learn how to write code like this?
This newsgroup is a good source. I strongly suggest the library as well.

First go to (http://accu.org/index.php/book_reviews) and find a few
books that you think might be useful, then write down their title,
author, and ISBN and take it to your local librarian. If your local
library doesn't have one or more of the books, tell the librarian that
you would like to do an inter-library loan.

Of course, if you find a book indispensable, go to the bookstore and buy
a copy.
I am interested in scientific programming applications, where the
same algorithm is applied to disparate models, and I'm thus
interested in learning how to increase the abstraction level of my
code (without sacrificing speed, of course!)
That is what the standard library is all about, a bunch of algorithms
that are applied to different models. I suggest starting there.
Dec 23 '06 #13

P: n/a

Daniel T. wrote:
"David Sanders" <dp*******@gmail.comwrote:
Daniel T. wrote:
I think it is important to note that the "extra work" you are
trying to avoid is adding 2 lines in your main every time you make
a new sub-class. That's not much...
>
In order to save you extra work in this case, the solution must
allow you to add a new class to main with only one line of extra
code, and the number of classes must be great enough to justify
the amount of code required to allow that one line to work.
Thanks again to everybody who offered suggestions. Daniel T.'s comes
closest to what I was imagining, although I'm not surprised I didn't
manage it myself -- any of the solutions seem to be rather
complicated and non-intuitive.

Maybe it seems complicated at first, but after you have seen the
patterns a few times, it gets to be quite simple.

In each class' cpp file, I create a global object. The constructor of
the global objects created log themselves in yet another object (the
"models" object inside the "modelMap()" function.) "main" then accesses
the "models" map and calls create on the appropriate factory.

The only tricky part is making sure that the "models" object is
constructed before any of the factory objects are, that is why the
models object is embedded in a function.
Where should I be looking to learn how to write code like this?

This newsgroup is a good source. I strongly suggest the library as well.
Your above description of the pattern you used is exactly the kind of
thing I'm interested in learning.
And it's exactly the kind of thing I don't know where to find. If you
have recommendations for specific books or book areas, I'd be very
grateful, since I do not have ready access to relevant books,
especially not to browse through, because of where I'm living.

For example, for the above trick/method, would I look in a book on C++
templates, on design patterns, or what? And what would I have searched
for in the newsgroup?

Thanks and best wishes,
David.

Dec 23 '06 #14

P: n/a
You could try reverse engineering the RTTI :) Probably more hassle than
it's worth.

Dec 23 '06 #15

P: n/a
"David Sanders" <dp*******@gmail.comwrote:
Daniel T. wrote:
"David Sanders" <dp*******@gmail.comwrote:
Where should I be looking to learn how to write code like this?
This newsgroup is a good source. I strongly suggest the library as
well.

Your above description of the pattern you used is exactly the kind
of thing I'm interested in learning. And it's exactly the kind of
thing I don't know where to find. If you have recommendations for
specific books or book areas, I'd be very grateful, since I do not
have ready access to relevant books, especially not to browse
through, because of where I'm living.
I can't really say because I don't know your skill level. For example,
"Modern C++ Design" by Andrei Alexandrescu is an excellent source for
this kind of stuff, but it might be too advanced for you. "Design
Patterns", by Gamma et al. is another good source but might be too
abstract for you. "Generic Programming and the STL" by Matthew Austern
is yet another.

The books by Scott Meyers are great mid-level books that may be either
too advanced or too simple for you..
For example, for the above trick/method, would I look in a book on
C++ templates, on design patterns, or what? And what would I have
searched for in the newsgroup?
For this specific example, it was asked once a few years ago on this
forum, I didn't know the answer at the time so I read the replies. When
you asked the question, I remembered the basic gist of the answers from
back then and worked out the exact solution. So my answer is to read
voraciously, and things will stick.
Dec 24 '06 #16

P: n/a

Daniel T. wrote:
"David Sanders" <dp*******@gmail.comwrote:
Daniel T. wrote:
"David Sanders" <dp*******@gmail.comwrote:
>
Where should I be looking to learn how to write code like this?
>
This newsgroup is a good source. I strongly suggest the library as
well.
Your above description of the pattern you used is exactly the kind
of thing I'm interested in learning. And it's exactly the kind of
thing I don't know where to find. If you have recommendations for
specific books or book areas, I'd be very grateful, since I do not
have ready access to relevant books, especially not to browse
through, because of where I'm living.

I can't really say because I don't know your skill level. For example,
"Modern C++ Design" by Andrei Alexandrescu is an excellent source for
this kind of stuff, but it might be too advanced for you. "Design
Patterns", by Gamma et al. is another good source but might be too
abstract for you. "Generic Programming and the STL" by Matthew Austern
is yet another.

The books by Scott Meyers are great mid-level books that may be either
too advanced or too simple for you..
Great, thanks for the specific recommendations. I'll get reading as
soon as I can.
My skill level is currently quite low -- I use inheritance and
templates in a basic way, let's say -- but I (hope I) can usually pick
up ideas reasonably well, I just didn't have a clue where to start
really.
For example, for the above trick/method, would I look in a book on
C++ templates, on design patterns, or what? And what would I have
searched for in the newsgroup?

For this specific example, it was asked once a few years ago on this
forum, I didn't know the answer at the time so I read the replies. When
you asked the question, I remembered the basic gist of the answers from
back then and worked out the exact solution. So my answer is to read
voraciously, and things will stick.
OK, thanks very much for your help -- looks like I've got some reading
to do.
Just wish I was still living near enough London to go and visit the
excellent bookshops there...

Thanks and best wishes,
David.

Dec 24 '06 #17

P: n/a
David Sanders wrote:
....
>
I have looked hard at the FAQ, and I cannot see anything that is
relevant (but please correct me if I'm wrong). Any suggestions or
pointers would be greatly appreciated.
Austria C++ generic factory does exactly this.

You can place implementations of your class anywhere (even in a
dynamically loaded binary) and then invoke the constructor.

somthing like:
usage.h
--------------------
#include "at_factory.h"

class BasicModel
{

virtual ~BasicModel() {}

virtual void DoSomthing() = 0;

};
----------------------

usage.cpp
----------------------
#include "usage.h"
....
BasicModel * m = at::FactoryRegister<
BasicModel, // interface class
at::DKy, // Special string key - could use std::string
Creator3P<
BasicModel, // repeat the interface class
at::DKy, // repeat the key type
int, // constructor parameter 1 type
int, // constructor parameter 2 type
int // constructor parameter 3 type
>
::Get().Create( "aa" )( 1,2,3 );
if ( m != 0 ) .. factory not found
....
-----------------------

impl.cpp
-----------------------

#include "usage.h"

class Modelaa : public BasicModel
{

virtual void DoSomthing() {}
public:
Modelaa( int, int, int );

};

// register the factory
AT_MakeFactory3P( aa, Modelaa, BasicModel, at::DKy, int, int, int );

------------------------
Dec 24 '06 #18

P: n/a
andrewmcdonagh wrote:
Nice design, my only input would be that its not usually a good idea to
have base classes know about derived classes - in your case this
knowledge is purely by id and pointer to factory method, instead of a
direct knowledge association.
I agree that as a rule, base classes should not "know" about any of
their derived classes - that is, the base class should not have any
dependencies on a class derived from it. And as you noted, the program
has kept such dependencies to a minimum. In fact, strictly speaking
BasicModel has no code dependencies on any of its derived classes that
its factory method creates. In its current form, BasicModel is able to
allocate any number and variety of Derived classes that may be declared
now or in the future.
To finish the design, I would move the CreateByName() method to a
ModelFactory class. This way we keep the ideal of base classes not
knowing about derived classes and more importantly, we have a design
the is compliant with the Single Responsability Principle.
I agree with your suggestion of adding a ModelFactory class as a
cleaner way to separate the division of responsibility among the
classes in this program.

Another improvement that I would like to make is to further foolproof
the design. In other words, I would like to require that all of
BasicModel's derived classes have to "register" or not be able to
compile. I think one strategy that would work would be to "coalesce"
BasicModel's derived classes with an intermediate class template - that
would take care of registering each derived class and verifying that it
implements the required functions.

This design would create dependencies between the coalescing class and
each class derived from it. Specifically, to "concept-check" each
class, the coalescing base class would have to have access to the
definition of the derived class. Nonetheless I think the design would
be perfectly reasonable. So I would say that if a program needs to
break a rule (and solves a real problem by doing so) then it should do
so openly, even brazenly - since nothing of any value is every achieved
by taking half-measures.

Greg

Dec 24 '06 #19

P: n/a

David Sanders wrote:
Many thanks to all for the suggestions. I have some work to do to
understand the answers, but at least I now understand the reason for
design patterns.
FWIW the main weaknesses of the spec AFAICS are that they expose raw
pointers and that you are restricted to a ctor with one comon set of
creation parameters.

You could look at boost::shared_ptr which provides some memory
management so you don't need to keep track of memory :
http://www.boost.org/libs/smart_ptr/shared_ptr.htm
and you could modify the input so that a class may be created with
arbitrary parameters. Code below is one simple way to do this. In
practise requires solid checking that the input is valid of course

regards
Andy Little
---------------------

#include <map>
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <sstream>

/*
create a model from stream with arbitrary params
*/

struct BasicModel{
typedef boost::shared_ptr<BasicModelptr;
virtual ~BasicModel(){}
virtual const char * sig() const = 0;
};

struct default_Model : BasicModel{
default_Model(){}
const char * sig() const {return "default model";}

static ptr make( std::istream & )
{
return ptr (new default_Model());
}
static const char* id(){ return "default";}
};
struct Modela : BasicModel{
Modela(int a){}
const char * sig() const {return "model a";}
static ptr make( std::istream & in)
{
int a;
in >a;
return ptr (new Modela(a));
}
static const char* id(){ return "a";}
};

struct Modelabc : BasicModel{
Modelabc(int a, int b,std::string const & c){}
const char * sig() const {return "model abc";}

static ptr make( std::istream & in)
{
int a, b;
std::string c;
in >a >b >c;
return ptr (new Modelabc(a,b,c));
}
static const char* id(){ return "abc";}
};

struct factory{
typedef std::map<
std::string,
BasicModel::ptr (*)(std::istream &)
model_map_type;
static model_map_type model_maker;
template <typename Model>
static void add_model()
{
model_maker[ Model::id()] = Model::make;
}
};

factory::model_map_type factory::model_maker
=factory::model_map_type();

int main()
{
factory::add_model<default_Model>();
factory::add_model<Modela>();
factory::add_model<Modelabc>();

std::stringstream stream;
BasicModel::ptr p =
factory::model_maker[default_Model::id()](stream);

std::cout << p->sig() <<'\n';
int a = 1;
stream << a;

p = factory::model_maker[Modela::id()](stream);
std::cout << p->sig() <<'\n';

int b = 2;
std::string c = "hello";
stream << a << b << c;
p = factory::model_maker[Modelabc::id()](stream);
std::cout << p->sig() <<'\n';

}

Dec 24 '06 #20

P: n/a


On Dec 23, 4:55 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
andrewmcdonagh wrote
kwikius wrote:
andrewmcdonagh wrote:
>You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.You've still not shown me any proof that my example is incorrect.
You have implied that it is incorrect several times however. Maybe now
you should either prove your point or apologise for making incorrect
statements.
I do indeed apologise, I saw the make_model_xzy functions and thought
they were part of the ABC, when in fact they aren't.

This is what lead me to say that the ABC would need changing when
adding another derived class.

Andrew

Dec 25 '06 #21

P: n/a
In article <11**********************@f1g2000cwa.googlegroups. com>,
"andrewmcdonagh" <an************@gmail.comwrote:
On Dec 23, 4:55 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
andrewmcdonagh wrote
kwikius wrote:
andrewmcdonagh wrote:
You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.You've still not
shown me any proof that my example is incorrect.
You have implied that it is incorrect several times however. Maybe now
you should either prove your point or apologise for making incorrect
statements.

I do indeed apologise, I saw the make_model_xzy functions and thought
they were part of the ABC, when in fact they aren't.

This is what lead me to say that the ABC would need changing when
adding another derived class.
I'm a little confused about one thing. Kwikius had to change main when
he added a new class. The OP specifically requested that 'main()'
conform to the OCP.
Dec 25 '06 #22

P: n/a


On Dec 25, 4:46 pm, "Daniel T." <danie...@earthlink.netwrote:
In article <1167047945.486690.253...@f1g2000cwa.googlegroups. com>,

"andrewmcdonagh" <andrewmcdon...@gmail.comwrote:
On Dec 23, 4:55 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
andrewmcdonagh wrote
kwikius wrote:
andrewmcdonagh wrote:
>You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.You've still not
shown me any proof that my example is incorrect.
You have implied that it is incorrect several times however. Maybe now
you should either prove your point or apologise for making incorrect
statements.
I do indeed apologise, I saw the make_model_xzy functions and thought
they were part of the ABC, when in fact they aren't.
This is what lead me to say that the ABC would need changing when
adding another derived class.I'm a little confused about one thing. Kwikius had to change main when
he added a new class. The OP specifically requested that 'main()'
conform to the OCP.
Sure, but something has to change in order to get the new object
registered, whether it be main or a Factory (ignoring of course the
possible dynamical loading of classes, etc).

So, I took the change to main() to be 'ok'

Dec 25 '06 #23

P: n/a
"andrewmcdonagh" <an************@gmail.comwrote:
"Daniel T." <danie...@earthlink.netwrote:
Kwikius had to change main when he added a new class. The OP
specifically requested that 'main()' conform to the OCP.

Sure, but something has to change in order to get the new object
registered, whether it be main or a Factory (ignoring of course the
possible dynamical loading of classes, etc).
Yet I was able to present a solution where no cpp file needed to be
changed to add a new sub-class (without any dynamical loading of classes
etc.) So I don't see how your assertion is correct.
So, I took the change to main() to be 'ok'
Despite the fact that changing main() was exactly what the OP wanted to
avoid. I.E., your solution didn't solve the OPs problem.
Dec 25 '06 #24

P: n/a

Daniel T. wrote:
Despite the fact that changing main() was exactly what the OP wanted to
avoid. I.E., your solution didn't solve the OPs problem.
You seem to be reading a lot into it AFAICS. It seems to me the OP just
wanted to know how to use a map. Anyway I decided to work on my
previous efforts to incorporate some of the ideas.

I have however tried to avoid intruding into the derived classes so
they can be used with other factories or alone.
Factory also tries to be more generic.
Poorest part is probbably the stream input which doesnt get any
checking, could also be made more generic.
Probably over the top for what the O.P wanted, but it beats watching
the box:-)

regards
Andy Little

Tested on VC7.1 and gcc4.1. should compile OK as one big file:

/*
factory demo
*/
// comment out to compile as separate files
// with headers
#define ALLINONE

#ifndef BASIC_MODEL_HPP_INCLUDED
#define BASIC_MODEL_HPP_INCLUDED

#include <boost/shared_ptr.hpp>

// abc model class
struct BasicModel{
typedef BasicModel base_type;
typedef boost::shared_ptr<BasicModelptr;
virtual ~BasicModel(){}
virtual const char * sig() const = 0;
};

#endif
//----------------------------------

#ifndef DEFAULT_MODEL_HPP_INCLUDED
#define DEFAULT_MODEL_HPP_INCLUDED
#include "basic_model.hpp"

// some concrete model

struct default_Model : BasicModel{
default_Model(int a, int b , int c){}
const char * sig() const {return "default model";}
};

#endif
//---------------------------------
#ifndef MODELA_HPP_INCLUDED
#define MODELA_HPP_INCLUDED
#ifndef ALLINONE
#include "basic_model.hpp"
#endif

// other concrete model

struct Modela : BasicModel{
Modela(int a){}
const char * sig() const {return "model a";}
};
#endif
//---------------------------------
#ifndef MODELABC_HPP_INCLUDED
#define MODELABC_HPP_INCLUDED

#include <iostream>
#ifndef ALLINONE
#include "basic_model.hpp"
#endif
#include <string>

// another concrete model

struct Modelabc : BasicModel{
Modelabc(int a, int b,std::string const & c){}
const char * sig() const {return "model abc";}

static ptr make( std::istream & in)
{
int a, b;
std::string c;
in >a >b >c;
return ptr (new Modelabc(a,b,c));
}
static const char* id(){ return "abc";}
};

#endif
//---------------------------------
#ifndef FACTORY_HPP_INCLUDED
#define FACTORY_HPP_INCLUDED

// generic factory traits classes

// per factory id
template <typename Factory, typename Object>
struct construction_id;

// per factory creation function
template <typename Factory, typename Object>
struct construction_function;

// get base class utility
template <typename Object>
struct get_base_type{
typedef typename Object::base_type type;
};

#endif
//---------------------------------

#ifndef ISTREAM_FACTORY_HPP_INCLUDED
#define ISTREAM_FACTORY_HPP_INCLUDED

#ifndef ALLINONE
#include "factory.hpp"
#endif
#include <map>
#include <string>
#include <iostream>
#include <boost/function.hpp>
#include <boost/function_equal.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <stdexcept>

// istream factory. create an object via an istream

template <typename BaseObject>
class istream_factory{
public:
// probably shouldnt be public ...
typedef boost::function<typename BaseObject::ptr(std::istream &)>
function;
typedef std::map< std::string, functionobject_map_type;
object_map_type object_maker;

// register a derived type
template <typename Object>
void add( const char* id)
{
BOOST_STATIC_ASSERT((boost::is_same<BaseObject, typename
get_base_type<Object>::type>::value));
object_maker[id] =
construction_function<istream_factory,Object>();
}
typename BaseObject::ptr make(std::istream & in)
{
std::string id;
in >id;

typename object_map_type::const_iterator i =
object_maker.find(id);
if( i == object_maker.end()){
throw std::invalid_argument("invalid construction id in
istream_factory");
}
return i->second(in);
}
};
// Use Daniel T's trick for factory init
template <typename BaseObject>
istream_factory<BaseObject>& get_istream_factory()
{
static istream_factory<BaseObjectfactory;
return factory;
}

// User id get function

template<typename Object>
const char * get_istream_construction_id()
{
typedef typename get_base_type<Object>::type base;
construction_id<istream_factory<base>,Objectid;
return id();
}

// struct to register type
// instantiate a static version in cpp file per object

template <typename Object>
struct register_with_istream_factory{
void register_()
{
static bool is_registered = false;
if( ! is_registered){
typedef typename get_base_type<Object>::type base;
construction_id<istream_factory<base>,Objectid;
get_istream_factory<base>(). template add<Object>(id());
is_registered = true;
}
}
register_with_istream_factory()
{
register_();
}
};

#endif
//---------------------------------
#ifndef BASIC_MODEL_IF_HPP_INCLUDED
#define BASIC_MODEL_IF_HPP_INCLUDED

//default non intrusive support for istream_factory
// for BasicModel derived classes
#ifndef ALLINONE
#include "basic_model.hpp"
#include "istream_factory.hpp"
#endif

// For O.P most( all) classes have common ctor params
// this partial specialisation covers those cases
// further specialisation is possible
// as shown below
template <typename Default>
struct construction_function<istream_factory<BasicModel>, Default>
{
BasicModel::ptr operator()( std::istream & in)const
{
int a, b, c;
in >a>b >c;
return BasicModel::ptr (new Default(a,b,c));
}
};

#endif
//----------------------------------
#ifndef DEFAULT_MODEL_IF_HPP_INCLUDED
#define DEFAULT_MODEL_IF_HPP_INCLUDED

// each derived class needs own id
//
#ifndef ALLINONE
#include "default_model.hpp"
#include "istream_factory.hpp"
#endif
template <>
struct construction_id<istream_factory<BasicModel>,defaul t_Model>
{
const char* operator()()const
{
return "default";
}
};

#endif
//----------------------------------
#ifndef MODELA_IF_HPP_INCLUDED
#define MODELA_IF_HPP_INCLUDED
#ifndef ALLINONE
#include "modela.hpp"
#include "istream_factory.hpp"
#endif

// customised istream_factory construction
// for Modela

template <>
struct construction_id<istream_factory<BasicModel>,Modela >
{
const char* operator()()const
{
return "a";
}
};

// Modela different ctor params so its
// construction function is further specialised...
template <>
struct construction_function<istream_factory<BasicModel>, Modela>
{
BasicModel::ptr operator()( std::istream & in)const
{
int a;
in >a;
return BasicModel::ptr (new Modela(a));
}
};

#endif
//------------------------------------
#ifndef MODELABC_IF_HPP_INCLUDED
#define MODELABC_IF_HPP_INCLUDED

// customised istream_factory construction
// for Modelabc
#ifndef ALLINONE
#include "modelabc.hpp"
#include "istream_factory.hpp"
#endif

template <>
struct construction_id<istream_factory<BasicModel>,Modela bc>
{
const char* operator()()const
{
return Modelabc::id();
}
};

// etcetera...
template <>
struct construction_function<istream_factory<BasicModel>, Modelabc>
{

BasicModel::ptr operator()( std::istream & in)const
{
return Modelabc::make(in);
}
};
#endif
//----------------SOURCE-----------------
//-----------main.cpp-----------
#ifndef ALLINONE
#include "default_model_if.hpp"
#include "modela_if.hpp"
#include "modelabc_if.hpp"
#endif
#include <sstream>

int main()
{
try{
istream_factory<BasicModel& factory
= get_istream_factory<BasicModel>();

std::stringstream stream;

int a =1, b= 2, c =3;
stream << get_istream_construction_id<default_Model>()
<< ' ' << 1 << ' '<< 2 << ' '<< 3 << '\n';
stream << get_istream_construction_id<Modela>()
<< ' ' << 4 << '\n';
stream << get_istream_construction_id<Modelabc>()
<< ' ' << 5 << ' ' << 6 << ' ' << "hello" << '\n';
std::cout << "stream contains\n";
std::cout << stream.str();
std::cout << "---------\n\n";
BasicModel::ptr p = factory.make(stream);
std::cout << p->sig() <<'\n';

p = factory.make(stream);
std::cout << p->sig() <<'\n';

p = factory.make(stream);
std::cout << p->sig() <<'\n';
}
catch (std::exception & e){
std::cout << e.what() <<'\n';
}
}
// register various models...
//-------default_model_if.cpp---
#ifndef ALLINONE
#include "basic_model_if.hpp"
#include "default_model_if.hpp"
#endif
static register_with_istream_factory<default_Model>
default_Model_istream_registered
= register_with_istream_factory<default_Model>();

//-------modela_if.cpp-------
#ifndef ALLINONE
#include "modela_if.hpp"
#endif
// Modela istream_factory regsitry cpp file
static register_with_istream_factory<Modela>
Modela_istream_registered
= register_with_istream_factory<Modela>();

//-----modelabc_if.cpp-------
#ifndef ALLINONE
#include "modelabc_if.hpp"
#endif

static register_with_istream_factory<Modelabc>
Modelabc_istream_registered
= register_with_istream_factory<Modelabc>();

// --------end-----------

Dec 26 '06 #25

P: n/a

andrewmcdonagh wrote:
On Dec 23, 4:55 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
andrewmcdonagh wrote
kwikius wrote:
andrewmcdonagh wrote:
You lost me I'm afraid. The design is simple and conforms to the spec
of the O.P.
Sure it does, I'm just commenting on that simple is not always correct
and other simple approaches can help over come these.You've still not shown me any proof that my example is incorrect.
You have implied that it is incorrect several times however. Maybe now
you should either prove your point or apologise for making incorrect
statements.

I do indeed apologise, I saw the make_model_xzy functions and thought
they were part of the ABC, when in fact they aren't.

This is what lead me to say that the ABC would need changing when
adding another derived class.
Thanks for that. Apologies for getting touchy, but I seem to have had
quite a bit of mistruths spread about me in C++ circles in the last few
months.
regards
Andy Little

Dec 26 '06 #26

This discussion thread is closed

Replies have been disabled for this discussion.