473,513 Members | 4,001 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Choosing a class using a variable without if-else

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
25 2114

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
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


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


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

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


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

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
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

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
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

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
"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

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
You could try reverse engineering the RTTI :) Probably more hassle than
it's worth.

Dec 23 '06 #15
"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

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
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
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

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


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
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


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
"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

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

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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1708
by: Piotr Sawuk | last post by:
Hello, I'm new in this group and new to c++ programming. And I already have my first question which wasn't answered by any text-book on c++ programming I have seen so-far: How can I define a class who's size is only known at the time the constructor gets executed -- without the overhead of pointer-managment (for copying) and without any...
2
2156
by: Jim Red | last post by:
hello first of all, i know, there are no classes in javascript. but i will use that word for better understanding of my question. here we go. i have three classes and need a reference to the parent class. could this be done by a reference, or just by constructing the class. function Class1() { this.class2 = new Class2();
8
1586
by: Jan-Ole Esleben | last post by:
Hi! I am new to this list, and maybe this is a stupid question, but I can't seem to find _any_ kind of answer anywhere. What I want to do is the following: I want to insert a class variable into a class upon definition and actually use it during definition. Manually, that is possible, e.g.:
166
8482
by: Graham | last post by:
This has to do with class variables and instances variables. Given the following: <code> class _class: var = 0 #rest of the class
7
1640
by: Phi! | last post by:
Hello everyone, any help with this would be appreciated as I have spent the past afternoon trying to sort it out. I have two questions based on the followiung information. I have two classes: - Class A { Method 1() {}
5
8722
by: Chris | last post by:
Hi, I don't get the difference between a struct and a class ! ok, I know that a struct is a value type, the other a reference type, I understand the technical differences between both, but conceptually speaking : when do I define something as 'struct' and when as 'class' ? for example : if I want to represent a 'Time' thing, containing...
9
1787
by: Larry Woods | last post by:
I have a method in my base class that I want ALL derived classes to use. But, I find that I can create a "Shadow" method in my derived class that "overrides" the method in my base class. Can't figure out what attribute to put on the base class method to prevent this. TIA, Larry Woods
15
2393
by: Joe Fallon | last post by:
I would like to know how you can figure out how much memory a given instance of a class is using. For example, if I load a collection class with 10 items it might use 1KB, and if I load it with 1000 items it might use 100KB. How do I measure the amount of memory used once the class is loaded? Thanks! -- Joe Fallon
37
5426
by: minkoo.seo | last post by:
Hi. I've got a question on the differences and how to define static and class variables. AFAIK, class methods are the ones which receives the class itself as an argument, while static methods are the one which runs statically with the defining class. Hence, my understanding is that static variables must be bound to the class defining the...
4
7928
by: alan | last post by:
AFAIK a template parameter must be completely determinable by the compiler at compile time, is this correct? Currently my problem is, I have a class which contains a std::vector. The size of this vector can be determined at the time an object of the class is constructed, and is assured not to change over the lifetime of the object. Now...
0
7270
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7178
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7397
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7563
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7125
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
1
5102
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
4757
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3252
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
470
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.