How can I instantiate a class with it's name? read my text ahead...

B

babakandme

Hi everybody:D

I've a string that contains the name of a class.
I want to instantiate from that class:

string strategyNameStr;
Strategy * strategy;

// All of the following classes are derived from Strategy.
// and """ strategyNameStr """ contains the name of one of the
following classes.
// e.g.
strategyNameStr = _T( "SimpleStrategy" );

SimpleStrategy * simStrategy;
MiddleStrategy * midStrategy;
HighStrategy * highStrategy;

How can I use """ strategyNameStr """ in the next line...
strategy = new ?

or
Is there at all any solution?

Thanks.
 
V

Victor Bazarov

I've a string that contains the name of a class.
I want to instantiate from that class:

string strategyNameStr;
Strategy * strategy;

// All of the following classes are derived from Strategy.
// and """ strategyNameStr """ contains the name of one of the
following classes.
// e.g.
strategyNameStr = _T( "SimpleStrategy" );

SimpleStrategy * simStrategy;
MiddleStrategy * midStrategy;
HighStrategy * highStrategy;

How can I use """ strategyNameStr """ in the next line...
strategy = new ?

or
Is there at all any solution?

#define INSTANTIATE_BY_NAME(var, str, clazz) \
if (str == #clazz) var = new clazz

strategy = 0;
INSTANTIATE_BY_NAME(strategy, strategyNameStr, SimpleStrategy);
if (!strategy)
INSTANTIATE_BY_NAME(strategy, strategyNameStr, MiddleStrategy);
if (!strategy)
INSTANTIATE_BY_NAME(strategy, strategyNameStr, HighStrategy);

or something like that.

V
 
P

Pete Becker

#define INSTANTIATE_BY_NAME(var, str, clazz) \
if (str == #clazz) var = new clazz

You don't need that Java-esque ugliness of misspelling class. The
preprocessor doesn't care about keywords.
 
B

babakandme

Hi,
thaks for the helps, but consider here:
The solution is somehow """HardCoding"""...


// Manager.h
typedef map< string, SStrategy * > SStrategyPool;
....
SStrategyPool SSPool;

// Manager.cpp
Manager::SomeFunction()
{
SStrategyPool::const_iterator iter;

// FlyWeighy pattern
iter = SSPool.find( strategyNameStr );

// if the strategy has not been added to the pool
if( iter == SSPool.end() )
{

/
*==============================================================================
Actually the problem is here, as you see, it is difficult to use some
"HardCoded" code here.
I mean the number of strategys may increase too much...
and it's not nice to use "HardCoding..."...
==============================================================================*/
// sStrategy = new ...?

// Add the new Strategy to the pool
SSPool.insert( strategyNameStr, sStrategy );

// call the desired SStrategy->DoIt();
sStrategy->DoIt();

}
else
{
// Use the old Added Strategy to the pool
// call the desired SStrategy->DoIt();
( iter->second )->DoIt();
}
}
 
V

Victor Bazarov

Pete said:
Sigh. Yet another "expert" on how people should write code. <g>

LOL

You and your duplicities! Did you mean that I'm the "expert" or
that the editor is?

I don't mean I have an editor who tells me how to write (I guess
you had one when you published your "Extensions", perhaps he/she
was too eager to edit, eh?). I actually meant the text editor
with syntax highlighting that makes "class" to show in bold type,
which I don't care for in that context.

V
 
P

Pete Becker

LOL

You and your duplicities! Did you mean that I'm the "expert" or
that the editor is?

Whoops, sorry: I meant the editor.
I don't mean I have an editor who tells me how to write (I guess
you had one when you published your "Extensions", perhaps he/she
was too eager to edit, eh?).

No, actually, the copy editors on my book were terrific. I learned a
lot, and the book is much better for it.
I actually meant the text editor
with syntax highlighting that makes "class" to show in bold type,
which I don't care for in that context.

Yes, I knew that.
 
M

ManicQin

dont you prefer a factory?

class strategyBuilder{
public:
static strategy* function buildStrategy(string objName)
{
if (objname == "sim")
return static_cast<strategy*>(new SimpleStrategy());
else if (objname == "mid")
return static_cast<strategy*>(new MiddleStrategy());

return NULL;
}
or something like that.

you could use it in the form of class/global function and you would
have to worry about pesky macro bugs.
 
B

babakandme

Yeah my Man:>
thanks...

Actually first I didn't want to use any HardCoding...
But now I see, here the FactoryMethod Pattern works...

Once again, thank you in advance...
 
O

Ondra Holub

Hi,
thaks for the helps, but consider here:
The solution is somehow """HardCoding"""...

// Manager.h
typedef map< string, SStrategy * > SStrategyPool;
...
SStrategyPool SSPool;

// Manager.cpp
Manager::SomeFunction()
{
SStrategyPool::const_iterator iter;

// FlyWeighy pattern
iter = SSPool.find( strategyNameStr );

// if the strategy has not been added to the pool
if( iter == SSPool.end() )
{

/
*==============================================================================
Actually the problem is here, as you see, it is difficult to use some
"HardCoded" code here.
I mean the number of strategys may increase too much...
and it's not nice to use "HardCoding..."...
==============================================================================*/
// sStrategy = new ...?

// Add the new Strategy to the pool
SSPool.insert( strategyNameStr, sStrategy );

// call the desired SStrategy->DoIt();
sStrategy->DoIt();

}

else
{
// Use the old Added Strategy to the pool
// call the desired SStrategy->DoIt();
( iter->second )->DoIt();

}
}

You can create for example some map of functions, which create
instances. Map may have as key text, which identifies the class. Then
you can add to this map many many different functions to create
instances.

If you need for every instance constructor with different parameters,
you can still achieve the above functionality - instead of storing
functions you can store instances of some building classes.

struct BaseClass
{
// ...
};

struct Builder
{
virtual ~Builder() { }
virtual BaseClass* operator()() = 0;
};

typedef
std::map<std::string, Builder> BuilderMap;

// adding new builder
struct SpecializedClass1: public BaseClass
{
SpecializedClass1(int, double);
};

struct SpecializedClass1Builder: public Builder
{
SpecializedClass1Builder(int i, double d)
: i_(i),
d_(d)
{
}

virtual BaseClass* operator()()
{
return new SpecializedClass1(i_, d_);
}
};

BuilderMap bm;
bm.insert(std::make_pair("SpecializedClass1",
SpecializedClass1Builder(2, 10.3)));
 
J

James Kanze

My editor does.

I don't believe it. I've never seen an editor that wouldn't
allow you to write just about anything. Do you mean it colors
it wrong, or that it indents incorrectly afterwards? (In the
latter case, of course, I'd wonder about the editor. All of the
various editors I've used for C++ know about the preprocessor,
and don't take macros into account for indenting.)

Or did you mean editor in the human sense: someone who reads
your code and corrects possible errors? Because human readers
do care about keywords---the presence of class in the macro will
immediately suggest a keyword to them, and probably cause some
confusion. Of course, for human readers, clazz isn't any
better; what you probably want is classname, or something like
that. (In the places I've worked, of course, classe or Klasse
would also work very well. A small advantage of being in a
non-English speaking environment:).)

Of course, any human editor would reject the code anyway, as
unnecessary and improper use of a macro, when better solutions
exist without the macro. The standard solution here is to use
some sort of map, mapping the name to a factory method (or a
factory interface). The map can be initialized in one of two
ways:

-- Dynamically, by initializers of static data. The author of
each class arranges for a static instance of something which
inserts his factory method or factory class into the
map---I'll usually map to a pointer to a factory interface,
with a constructor which does the registration; each class
derives from the interface, providing the necessary
function, and defines a static instance of its derived
class.

Of course, in this case, the map itself should be a
singleton, to avoid order of initialization issues with it.

I've even used this method with dynamic linking: when the
lookup in the map failed, I derived the name of a dynamic
object (.dll or .so, depending on the system) and tried to
load it, then tried again in the map. If loading it loaded
a static instance of the factory object, the second lookup
would find the factory object. In this case, you can even
find classes that weren't written yet when the program was
installed.

Of couse, you don't want to do this unless it's necessary.

-- Statically, using a simple array of struct's:

struct FactoryMapEntry
{
char const* className ;
Base* (* factoryMethod)() ;
} ;

This has the advantage of simplicity, and avoids any issues
of order of initialization, but it does mean that you have
to write the initialization of the map in C++, compile it,
and link it into your code. Or rather, someone or something
has to write it; I imagine that in most cases, you'd
generate it automatically by means of a shell script
invoked from the makefile. Supposing, of course, some well
defined naming convention for the factory methods (e.g.
createXXX for class XXX---or maybe create< XXX >(), with an
appropriately defined function template).

For lookup, of course, std::find_if with an appropriate
predicate will do the trick nicely.

This method means that once (statically) linked, the
available classes cannot change, and the complete map is
available everywhere during initialization of static
objects.

I can't remember using this for factory methods, but I do it
often enough for other things that I've a generic template
to automatically generate the table entries and the
necessary predicate for std::find_if.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top