Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Design of loadable class

0 views
Skip to first unread message

AlfC

unread,
Aug 22, 2007, 8:15:29 AM8/22/07
to
Hi,

I have been playing around with a class that can load an instance
from a file. After trying different approaches I realize that the
simpler and more "encapsulaed" approach was to add a static function
to the class that takes care of the loading.

class A{
A(){} // this constructs an empty instance which can be invalid for
the user
public:
static A load(string filename); //will return a valid copy of A
//my need and proper copy constructor depending on the application
protected:
.. fields ..
};

by doing this load can automatically access to the default constructor
and all the private members of A in order to construct it from the
file

and then I use this syntax for loading:

A a = A::load(file);

which is a syntax that I like because it is very clear.
I rejected other possibilities like (i) passing the filename to the
constructor because the syntax is not so clear then, e.g. A a =
A(filename) or (ii) creating a member function load that can encourage
to create the object in an invalid state, eg. A a; a.load(file);

However the A::load solution is some how redundant, even worst if A is
defined in a very nested namespace, the call will then be very
specific but too much redundant.

namespace1::namespace2::A a =
namespace1::namespace2::A::load("filename");

My goal is now to get rid of all this redundancy in a generic way,
so I come up with an extension of the solution (that I think it is
related to the "command" idiom), that consist in creating a reausable
"load" class (with no information about A) that only contains the name
of the file and is passed to the A constructor, the problem now is
that I need to derive from a new class the original class to keep
things clear and I am not sure this is a great solution because it
involves creating a lot of classes, although "class load" can be
reused for something else.

//at global namespace:
namespace command{
class load{
public:
load(string f) : file(f){}
string file;
};
}

//and in the same namespace where A is defined:
class Aloadable : public A{
Aloadable() : A(){}
public:
Aloadable(generic::load l) : A(A::load(l.file)){}
};

and then the syntax is simplified to:

namespace1::namespace2::Aloadable = command::load(file);
and then we forget about the original A under normal use.

This achives the goal but it seems like a complicated solution,

Is there a better design around?

note that this is a much simpler problem than the persistency problem,
class A (or class Aloadable) don't need to be saved or even have a
assigment operator=, etc.

Thank you,
Alfredo


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Alberto Ganesh Barbati

unread,
Aug 22, 2007, 2:22:08 PM8/22/07
to
AlfC ha scritto:

> Hi,
>
> I have been playing around with a class that can load an instance
> from a file. After trying different approaches I realize that the
> simpler and more "encapsulaed" approach was to add a static function
> to the class that takes care of the loading.
>
> <snip>

>
> A a = A::load(file);
>
> which is a syntax that I like because it is very clear.

I agree that it is very clear. However, you need to make a copy of A.
That can be a performance issue unless A is very light and/or some
ref-counted internal allows you to implement a cheap copy.

> I rejected other possibilities like (i) passing the filename to the
> constructor because the syntax is not so clear then, e.g. A a =
> A(filename) or (ii) creating a member function load that can encourage
> to create the object in an invalid state, eg. A a; a.load(file);

I agree with that two phase construction (i.e.: a.load(file)) is not a
good design, but I can't see anything wrong with passing the filename in
the constructor... I'd go for that solution, if I were you. For extra
safety, be sure to declare the constructor "explicit".

> However the A::load solution is some how redundant, even worst if A is
> defined in a very nested namespace, the call will then be very
> specific but too much redundant.
>
> namespace1::namespace2::A a =
> namespace1::namespace2::A::load("filename");

Yup. That's not very nice to see. However, in the next C++ revision we
will have the improved "auto", so you will someday be able to write it
like this:

auto a = namespace1::namespace2::A::load("filename");

> //at global namespace:
> namespace command{
> class load{
> public:
> load(string f) : file(f){}
> string file;
> };
> }
>
> //and in the same namespace where A is defined:
> class Aloadable : public A{
> Aloadable() : A(){}
> public:
> Aloadable(generic::load l) : A(A::load(l.file)){}
> };
>
> and then the syntax is simplified to:
>
> namespace1::namespace2::Aloadable = command::load(file);
> and then we forget about the original A under normal use.

Apart from the fact I don't see the need to introduce the Aloadable
class (which makes the whole approach very convoluted, IMHO), it's not
much different than having the A ctor take the filename directly.

If you want to have the word "load" appear explicitly on the
construction line, a much simpler way is the following:

namespace commmand
{
enum ELoadCommand { load };
}

class A
{
public:
A(commmand::ELoadCommand, string f);
};

then you construct with:

namespace1::namespace2::A a(command::load, file);

This approach allows you to provide other "commands" in addition to load
(for example: "new"), while maintaining the same level of expressiveness.

HTH,

Ganesh

Bart van Ingen Schenau

unread,
Aug 22, 2007, 6:35:06 PM8/22/07
to
AlfC wrote:

How about this, very generic, way:
using namespace1::namespace2::A;
A a = A::load("filename");

If you put the using declaration at a small enough scope, the risk of
name clashes will be extremely small.
And if you place the using declaration immediately above the use of A,
then it is still very obvious which class A refers to.

<snip>
> Thank you,
> Alfredo
>
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

AlfC

unread,
Aug 23, 2007, 12:31:06 PM8/23/07
to
Thank you for you answer.

>I agree that it is very clear. However, you need to make a copy of A.
>That can be a performance issue unless A is very light and/or some
>ref-counted internal allows you to implement a cheap copy.

I am not an expert in this... but is there something in the design
that stops a (good) compiler from optimizing the copy operation?
(I am basing my question in this
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9
,
isn't it applicable in this case?)

> If you want to have the word "load" appear explicitly

...that is part of the goal...

> on the
> construction line, a much simpler way is the following:
>
> namespace commmand
> {
> enum ELoadCommand { load };
> }
>
> class A
> {
> public:
> A(commmand::ELoadCommand, string f);
> };
>
> then you construct with:
>
> namespace1::namespace2::A a(command::load, file);

Ok, I will consider this option, thank you.

> This approach allows you to provide other "commands" in addition to load
> (for example: "new"), while maintaining the same level of expressiveness.

In fact, this is one of the issues I had in mind when possing the
question, how to extend this solution to other "commands". There are
other class that make more sense to be "read" from a stream instead of
loaded from a file, and some other class have both cases, so I
imagined some unified syntax that works like this:

B b = command::read(somepath); //sometimes
B b = command::load(someistream); //some other times

and the proposed solutions actually will work for both cases, just by
adding a class called "read" analoge to "load".

But of course your proposed solution can be used too. Having said
that, I think my first solution (static member) is a little bit more
flexible in this case because it allows "read" and "load" to share
common code, because they can call the same private constructor (for
example a non trivial default constructor). I think it is the need for
different command that shows the appeal for a static function, instead
of many constructors (one for load, one for read) with repeated code.
But I agree it is still arguable, after all my solution needs to
define a secondary ugly class (Aloadable).

Thank you,
Alfredo

AlfC

unread,
Aug 23, 2007, 12:30:26 PM8/23/07
to

> How about this, very generic, way:
> using namespace1::namespace2::A;
> A a = A::load("filename");

yes, I thought about that and thank you for the answer. In fact the
current design (without the derived class) forces me to do that very
often. This can work in many cases, I was looking for something that
also can be used without exposing the namespace (or part of it); so it
can be a solution for once and for all.

BTW at some point this issue made me wonder if there is a way of
restricting the scope of "using" without creating a C block.
Something like:
FOR namespace1::namespace2::{ //(not real code)


A a = A::load("filename");
}

... then use "a" without being out of scope.

I know something like this (based on curly brackets) is confusing, but
I think the point is clear, how to restrict "using" and "using
namespace" without interfering with the program flow. ie how to
distinguish a "syntactic block" from the usual "programming block". It
seems that there is now way to this right now. Isn't it?

Thanks,
Alfredo


--

ap...@student.open.ac.uk

unread,
Aug 23, 2007, 3:02:10 PM8/23/07
to
On 22 Aug, 13:15, AlfC <alfredo.cor...@gmail.com> wrote:
> Hi,
>
> I have been playing around with a class that can load an instance
> from a file.

ACE includes something like this. It is called the Service
Configurator pattern. I used it with a previous employer working on a
project that used an XML file to specify a pipeline of components that
plugged together. The components were loaded from shared libraries.
The component names, their libraries, and the join points (routines to
call for send and receive) were all specified in the XML. See
www.cs.wustl.edu/~schmidt/PDF/Svc-Conf.pdf for a detailed description
of the pattern.

Regards,

Andrew Marlow

Bart van Ingen Schenau

unread,
Aug 23, 2007, 4:14:27 PM8/23/07
to
AlfC wrote:

>
>> How about this, very generic, way:
>> using namespace1::namespace2::A;
>> A a = A::load("filename");
>
> yes, I thought about that and thank you for the answer. In fact the
> current design (without the derived class) forces me to do that very
> often. This can work in many cases, I was looking for something that
> also can be used without exposing the namespace (or part of it); so it
> can be a solution for once and for all.

If exposing even a single name from a namespace is a problem at a
certain point in the code, I would opt for shortening the namespace
name by using an alias, and then explicitly mention the namespace
(alias) in the declaration.

But then, I don't know in what kind of environment you work. I have
never had any troubles with using declarations.

>
> BTW at some point this issue made me wonder if there is a way of
> restricting the scope of "using" without creating a C block.
> Something like:
> FOR namespace1::namespace2::{ //(not real code)
> A a = A::load("filename");
> }
> ... then use "a" without being out of scope.
>
> I know something like this (based on curly brackets) is confusing, but
> I think the point is clear, how to restrict "using" and "using
> namespace" without interfering with the program flow. ie how to
> distinguish a "syntactic block" from the usual "programming block". It
> seems that there is now way to this right now. Isn't it?

There is indeed nothing like it in C++.
It sounds like a nice concept, but I think it will open up a big can or
worms very quickly.
One problem that I already see with the concept, is that people will
immediately start asking for partially-overlapping 'name scopes', for
code like this:

FOR 1 ::namespace1
// use names from namespace1 without qualification
FOR 2 ::namespaceA
// use names fom both namespaces
ENDFOR 1 // don't need namespace1 anymore
// use names from namespaceA
ENDFOR 2 // don't need namespaceA anymore

With this kind of code, it will soon be next to impossible to tell from
which namespaces the names are in scope at a particular point in the
code.
And disallowing such partially overlapping 'name scopes' will either
give you code that is unreadable due to all the opening and closing
of 'name scopes' (when closing FOR 1 in the example above, you must
first close FOR 2 and then re-open it), or you get code where the 'name
scopes' practically coincide with the logical blocks of the code (which
is effectively the current situation).

>
> Thanks,

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Alberto Ganesh Barbati

unread,
Aug 23, 2007, 7:12:48 PM8/23/07
to
AlfC ha scritto:

> Thank you for you answer.
>
>> I agree that it is very clear. However, you need to make a copy of A.
>> That can be a performance issue unless A is very light and/or some
>> ref-counted internal allows you to implement a cheap copy.
>
> I am not an expert in this... but is there something in the design
> that stops a (good) compiler from optimizing the copy operation?
> (I am basing my question in this
> http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9
> ,
> isn't it applicable in this case?)

First of all, the compiler is *allowed* to omit the copy, but it isn't
obliged to do so. Secondly, most compiler currently omit the copy only
in the RVO (return value optimization) case, that is:

// cut&pasted from the link above
Foo rbv()
{
...
return Foo(42, 73); // returned object constructed HERE!
}

Optimizing a case like this:

Foo rbv()
{
Foo f; // returned object constructed HERE
... // do something with f
return f;
}

is a completely different case, called NRVO for "named" return value
optimization, and AFAIK only few compilers currently do that. The
situation is bound to improve in the future, hopefully.

Anyway, the main problems are that you can't be sure that the copy does
*not* happen and that you must provide a public copy constructor even if
your class in not supposed to be copyable during normal use.

The future introduction in C++0x of move constructors may alleviate the
situation a bit, by providing means to at least have some cheap
alternative in case the compiler is not able to omit the copy.

> In fact, this is one of the issues I had in mind when possing the
> question, how to extend this solution to other "commands". There are
> other class that make more sense to be "read" from a stream instead of
> loaded from a file, and some other class have both cases, so I
> imagined some unified syntax that works like this:
>
> B b = command::read(somepath); //sometimes
> B b = command::load(someistream); //some other times
>
> and the proposed solutions actually will work for both cases, just by
> adding a class called "read" analoge to "load".
>
> But of course your proposed solution can be used too. Having said
> that, I think my first solution (static member) is a little bit more
> flexible in this case because it allows "read" and "load" to share
> common code, because they can call the same private constructor (for
> example a non trivial default constructor). I think it is the need for
> different command that shows the appeal for a static function, instead
> of many constructors (one for load, one for read) with repeated code.
> But I agree it is still arguable, after all my solution needs to
> define a secondary ugly class (Aloadable).

I'm not totally against "named constructors" (i.e.: static function
members that acts "like" constructors). I agree that they are very
expressive. I'm just worried about the potential extra copy, but if you
know which compiler you are working on and don't care about porting the
code to other compilers then you shouldn't be bothered by that.

About the repeated code between constructors, some of the code could be
factored out in a common static member. Anyway, C++0x is probably going
to introduce constructor delegation, allowing a constructor to delegate
part of its execution to another constructor, thus removing the repeated
code problem.

HTH,

Ganesh

Dave Harris

unread,
Aug 23, 2007, 7:12:01 PM8/23/07
to
alfredo...@gmail.com (AlfC) wrote (abridged):

> A a = A::load(file);
This is OK, although not very flexible if A has subclasses.


> A a = A(filename)

I don't really understand what is wrong with this. I can understand
wanting a type to denote filenames as opposed to other kinds of string,
thus:
A a = A( Filename(filename) );

However, your approach seems to want to introduce the notion of commands
in general and a specific kind of command called "load". To me this seems
like needless complication when all we need is a constructor. Similarly I
don't see that the subclass Aloadable adds any value.

If you want to include the word "load" somewhere, why not add it as a
enum?
enum Load { load };

class A {
public:
A( Load load, const std::string &filename );
///
};

A a = A( load, filename );

or even:
A a( load, filename );

which also avoids repeating the name of the class.

-- Dave Harris, Nottingham, UK.

Bob Hairgrove

unread,
Aug 24, 2007, 10:53:38 AM8/24/07
to

On Wed, 22 Aug 2007 06:15:29 CST, AlfC <alfredo...@gmail.com>
wrote:

>Hi,
>
> I have been playing around with a class that can load an instance
>from a file. After trying different approaches I realize that the
>simpler and more "encapsulaed" approach was to add a static function
>to the class that takes care of the loading.
>
>class A{
> A(){} // this constructs an empty instance which can be invalid for
>the user
> public:
> static A load(string filename); //will return a valid copy of A
> //my need and proper copy constructor depending on the application
> protected:
> .. fields ..
>};
>
>by doing this load can automatically access to the default constructor
>and all the private members of A in order to construct it from the
>file
>
>and then I use this syntax for loading:
>
>A a = A::load(file);
>
>which is a syntax that I like because it is very clear.

Yes ... congratulations, you have just "re-discovered" the Factory
pattern! However, there are practical considerations which have more
to do with memory management, and (maybe) less with actual C++
issues, which make most people tend to favor returning a pointer to a
(virtual base??) class instead of an object.

There are so many advantages to this approach (i.e. returning a
pointer instead of an object) that most people will eventually put
all the "factory" code into a shared library ... and THEN you might
have some memory management issues...

Maybe you should Google for "Factory" and "Abstract Factory"
patterns...

>I rejected other possibilities like (i) passing the filename to the
>constructor because the syntax is not so clear then, e.g. A a =
>A(filename) or (ii) creating a member function load that can encourage
>to create the object in an invalid state, eg. A a; a.load(file);
>
>However the A::load solution is some how redundant, even worst if A is
>defined in a very nested namespace, the call will then be very
>specific but too much redundant.
>
>namespace1::namespace2::A a =
>namespace1::namespace2::A::load("filename");
>
>My goal is now to get rid of all this redundancy in a generic way,
>so I come up with an extension of the solution (that I think it is
>related to the "command" idiom), that consist in creating a reausable
>"load" class (with no information about A) that only contains the name
>of the file and is passed to the A constructor, the problem now is
>that I need to derive from a new class the original class to keep
>things clear and I am not sure this is a great solution because it
>involves creating a lot of classes, although "class load" can be
>reused for something else.

Not the "Command idiom" (or pattern), but "Factory" is probably what
you want. The "Command" pattern has more to do with being "undoable",
IIRC...

>//at global namespace:
>namespace command{
> class load{
> public:
> load(string f) : file(f){}
> string file;
> };
>}
>
>//and in the same namespace where A is defined:
>class Aloadable : public A{
> Aloadable() : A(){}
> public:
> Aloadable(generic::load l) : A(A::load(l.file)){}
>};

The main drawback to this approach is that class load must "know
about" ALL of the loadable classes ... any time a new one is added,
you have to change the "loader" class. I find it much simpler to use
factory classes, or at least factory (static) functions which can be
defined on a per-class basis. Of course, you can use abstract factory
classes and override the appropriate "loader" functions in the
derived classes; however, I think this is only useful with very large
class hierarchies.

>and then the syntax is simplified to:
>
>namespace1::namespace2::Aloadable = command::load(file);
>and then we forget about the original A under normal use.
>
>This achives the goal but it seems like a complicated solution,
>
> Is there a better design around?

Yes ... if there is no need to save the state of any classes, it
becomes much simpler.

Good luck!

--
Bob Hairgrove
NoSpam...@Home.com

Jeff Flinn

unread,
Aug 24, 2007, 10:54:29 AM8/24/07
to

"AlfC" <alfredo...@gmail.com> wrote in message
news:1187749506.5...@i38g2000prf.googlegroups.com...

> Hi,
>
> I have been playing around with a class that can load an instance
> from a file. After trying different approaches I realize that the

Have you seen: http://www.boost.org/libs/serialization/doc/index.html.

This addresses(one way or another) all of those issues that you haven't yet
run into.

Jeff Flinn

AlfC

unread,
Aug 26, 2007, 12:22:28 PM8/26/07
to
> However, your approach seems to want to introduce the notion of commands
> in general and a specific kind of command called "load". To me this seems
> like needless complication when all we need is a constructor.


Many people suggested to go back to a simple constructor, much
simpler, more efficient in most compilers too. I was think that I can
even keep the syntax the sample and move the load class as a parameter
for certain class constructor. This has the advantage of being
expressive and efficient, and doesn't need a copy constructor. Does
anybody has any problem with the following redesign:

namespace command{
class load{
string filename;
};
}
verynested namespace{
class A{
A(command::load const& L){
... load stuff from L.filename ...
}
};
}

and then use as following

verynested_namespace::A a=command::load("filename"); // same desired
syntax!

in fact I could take an step further and could even make this more
"standard" by getting rid of class command::load and just use
boost::filesystem::path (or other library with filesystem
capabilities)
...
A(boost::filesystem::path const& P){ ... load stuff from P ... }
...

for classes that *don't* have a constructor from std::string or char[]
I can initialize right away simply as
verynested_namespace A("filename");

for classes that *have* constructor from string or char[] I can do:
verynested_namespace::A a=boost::filesystem::path("filename");
it is clear that this is a "load" operation because: what else can we
do with a path at initialization other than load?

I can add the explicit optionally to forbid the first option in which
the string is casted to a boost::filesystem::path.

The advantage I lost is that I have to move the (a lot of) common
code of command::load and (let's say) command::read to some other
static function, which is something I particularly dislike.

AlfC

unread,
Aug 26, 2007, 12:21:38 PM8/26/07
to

> >//at global namespace:
> >namespace command{
> > class load{
> > public:
> > load(string f) : file(f){}
> > string file;
> > };
> >}
>
> >//and in the same namespace where A is defined:
> >class Aloadable : public A{
> > Aloadable() : A(){}
> > public:
> > Aloadable(generic::load l) : A(A::load(l.file)){}
> >};

generic::load is really command::load, if mixed up example codes

>
> The main drawback to this approach is that class load must "know
> about" ALL of the loadable classes ... any time a new one is added,
> you have to change the "loader" class.

class command::load knows nothing about other classes and could be
reused.

"A" can be renamed as a hidden "Abase" and "Aloadable" can be renamed
to "A".

AlfC

unread,
Aug 26, 2007, 12:23:08 PM8/26/07
to
>
> I'm not totally against "named constructors" (i.e.: static function
> members that acts "like" constructors). I agree that they are very
> expressive. I'm just worried about the potential extra copy, but if you
> know which compiler you are working on and don't care about porting the
> code to other compilers then you shouldn't be bothered by that.
>
> About the repeated code between constructors, some of the code could be
> factored out in a common static member. Anyway, C++0x is probably going
> to introduce constructor delegation, allowing a constructor to delegate
> part of its execution to another constructor, thus removing the repeated
> code problem.

Maybe I should have stressed from the beginning that the loadable
classes in some cases are read from a file (load) and in some cases
read from stream (read), so naturally this two constructions will have
a lot in common, however if both are normal constructors one can not
call the other. In my original design static function load can call
static function read.


I would like to know more about this "construction delegation" and
other new features of c++0x but I couldn't find a good source for
these proposals with clear illustrative code and the explaining the
reasons, all the info about c++0x seems to be very scattered and too
much technical.

Chris Thomasson

unread,
Aug 26, 2007, 11:11:48 PM8/26/07
to
"AlfC" <alfredo...@gmail.com> wrote in message
news:1187749506.5...@i38g2000prf.googlegroups.com...
> Hi,
>
[...]

> However the A::load solution is some how redundant, even worst if A is
> defined in a very nested namespace, the call will then be very
> specific but too much redundant.
>
> namespace1::namespace2::A a =
> namespace1::namespace2::A::load("filename");
[...]

Here is, IMHO, a fairly good solution for organizing your library away into
individual "versioned" components that can undergo customized abstraction:


-----------------
#include <string>
#include <cstdio>

// Common Commands Version 001
//__________________________________________________
namespace yourlibsys {
namespace common {
namespace command {
namespace v001 {
class load {
std::string m_name;

public:
load(std::string const& name)
: m_name(name) {}

load(char const* const name)
: m_name(name) {}

public:
std::string const& load_name() const {
return m_name;
}
};
}}}} // namespace yourlibsys::common::command::v001


// Custom Commands Version 001
//__________________________________________________

// setup system abstraction mutators
#if ! defined(YOURLIBSYS_CUSTOM_COMMON_CMD_VER)
#define YOURLIBSYS_CUSTOM_COMMON_CMD_VER() v001
#endif

namespace yourlibsys {
namespace custom {
namespace command {
namespace v001 {
namespace {
// using common commands version 001
namespace cmd_common =
yourlibsys::common::command::
YOURLIBSYS_CUSTOM_COMMON_CMD_VER();
}

class A {
cmd_common::load const& m_cmd_load;

public:
A(cmd_common::load const& cmd_load)
: m_cmd_load(cmd_load) {
// open filename, do whatever...
printf("(%p)-A(load(%s));\n",
(void*)this, m_cmd_load.load_name().c_str());
}

public:
cmd_common::load const& load_cmd() const {
return m_cmd_load;
}
};
}}}} // namespace yourlibsys::custom::command::v001


// Abstract Version
//__________________________________________________


// setup abstraction mutators
#if ! defined(YOURLIB_COMMON_COMMAND_VER)
#define YOURLIB_COMMON_COMMAND_VER() v001
#endif

#if ! defined(YOURLIB_CUSTOM_COMMAND_VER)
#define YOURLIB_CUSTOM_COMMAND_VER() v001
#endif


// abstract the library
namespace yourlib {
namespace common {
namespace command =
yourlibsys::common::command::
YOURLIB_COMMON_COMMAND_VER();
}

namespace custom {
namespace command =
yourlibsys::custom::command::
YOURLIB_CUSTOM_COMMAND_VER();
}
}


// Application level
//__________________________________________________


// local application-level abstraction
namespace cmd_common = yourlib::common::command;
namespace cmd_custom = yourlib::custom::command;


int main(void) {
{
cmd_custom::A a(cmd_common::load("resource_name"));

printf("(%p)-a(%s);\n",
(void*)&a, a.load_cmd().load_name().c_str());
}

puts("\n\n\n\
_______________________\npress <enter> to exit...\n");
return getchar();
}

-----------------

That code is an analog of the following basic technique:

http://groups.google.com/group/comp.lang.c++/msg/6344cdcc315a5f07

You can define the following macro functions for fairly fine-grain
system-level and user-level customized abstractions:

- YOURLIBSYS_CUSTOM_COMMON_CMD_VER
- YOURLIB_COMMON_COMMAND_VER
- YOURLIB_CUSTOM_COMMAND_VER


Do you think something like that can help you?

Tom Lynch

unread,
Aug 27, 2007, 9:02:14 AM8/27/07
to
On Aug 25, 12:53 am, Bob Hairgrove <NoSpamPle...@Home.com> wrote:
> Yes ... congratulations, you have just "re-discovered" the Factory
> pattern! However, there are practical considerations which have more
> to do with memory management, and (maybe) less with actual C++
> issues, which make most people tend to favor returning a pointer to a
> (virtual base??) class instead of an object.
>
> There are so many advantages to this approach (i.e. returning a
> pointer instead of an object) that most people will eventually put
> all the "factory" code into a shared library ... and THEN you might
> have some memory management issues...
>
> Maybe you should Google for "Factory" and "Abstract Factory"
> patterns...

I agree.

I would normally return a shared_ptr from the factory function
("load") as well. Simplifies a lot of stuff and gets rid of the
overhead of unnecessary copying.

The other thing to note is that it would be wise to separate the
mechanism that you use the construct the objects from the mechanism
used to determine which object to construct.

In this case you're using a resource name (e.g. a filename) and
potentially its contents to determine which type of object to marshal
from its serial form in-file, and then constructing that type of
object from the file. The two things should be somewhat divorced from
one another.

Many factory setups have a concept of "abstract creators" -- a series
of these are registered, each offering a predicate on the "key
type" (in this case the filename / file contents) which tests whether
the key corresponds to the type of object they offer to create. Then
the factory function can test each creator in sequence until it finds
a match, whereupon it constructs an object as requested.

Tom

Dave Harris

unread,
Aug 28, 2007, 6:03:38 PM8/28/07
to
Alberto...@libero.it (Alberto Ganesh Barbati) wrote (abridged):

> About the repeated code between constructors, some of the code
> could be factored out in a common static member.

Or non-static member. Then it can assign to member variables.

-- Dave Harris, Nottingham, UK.

--

0 new messages