Dynamic Class Loading

A

Aguilar, James

My previous example used the concept of a Shape class heirarchy, so I will
continue with that.

Suppose I have something like fifty different shapes, and I am trying to
instantiate one of them. The trick is, the instatiation will be based on a
string with the exact same name as the type that I am trying to instantiate.
Obviously, writing a fifty element long switch statement is an inferior
solution. So, how can I instantiate based on strings? Is there a method
provided in the standard, or am I up a creek without a paddle?
 
V

Victor Bazarov

My previous example used the concept of a Shape class heirarchy, so I will
continue with that.

Suppose I have something like fifty different shapes, and I am trying to
instantiate one of them. The trick is, the instatiation will be based on a
string with the exact same name as the type that I am trying to instantiate.

The name of a type only exists in the source code. Once the code has
been compiled and linked, there are no type names, and often there are
no distinguishable types either. Just a bunch of functions and const
data that control the behaviour of the program until the run-time data
come in.
Obviously, writing a fifty element long switch statement is an inferior
solution.

It's the only solution, AFA C++ is concerned. Variations on the theme
include tables, maps, etc., but essentially they lead to the same task:
association of a string with some function that causes the instantiation
of the corresponding class or classes.
So, how can I instantiate based on strings? Is there a method
provided in the standard, or am I up a creek without a paddle?

No method is provided in the language to associate strings with any
types unless you do it yourself. Do not call simple programming task
"up a creek without a paddle". Free cheese exists only in a mousetrap.

V
 
P

Phlip

My previous example used the concept of a Shape class heirarchy, so I will
continue with that.

Suppose I have something like fifty different shapes, and I am trying to
instantiate one of them. The trick is, the instatiation will be based on a
string with the exact same name as the type that I am trying to instantiate.
Obviously, writing a fifty element long switch statement is an inferior
solution. So, how can I instantiate based on strings? Is there a method
provided in the standard, or am I up a creek without a paddle?

Read /Design Patterns/, and use either Prototype, Class Factory, or Factory
Method.

Also, why do you need an instance? Does each class really have state? Could
you use Flyweight?
 
A

Aguilar, James

Victor Bazarov said:
Aguilar, James wrote:
[snip]

OK, so there's no language construct that lets me do that. The second best
idea is a HashMap, I guess, with the string and the class. However, as you
said, there is no way to represent simply a type in C++. So what should I
put as the data in the hashmap? A pointer to a constructor? I don't think
that works, does it? So, a pointer to a static member method? Something
like this:

//In Something.h
class Something : public Foo
{
public:
void method1();
Something(int n);
static Something* initThis(int n);
}

//In Something.cpp
static Something* Something::initThis(int n)
{
return new Something(n);
}

//In the method that fills the hashmap when the program runs
void fillHashMap()
{
...
map.put("Something", (Something::initThis));
...
//This assumes map is a template of type <string, Something* (*)(int n)>
}

//Then, to get the method that would instantiate Something:
void someothermethod(string classToGet)
{
Something* (initFun*)(int n) = map.get(classToGet);
}

That code would work, right? (Something::initThis)(int n) would resolve to
a pointer to that method, unless I've got my syntax wrong. Please correct
me if I don't have it right.
 
A

Aguilar, James

Phlip said:
Aguilar, James wrote:

Also, why do you need an instance? Does each class really have state? Could
you use Flyweight?

Well, I'm pretty sure I need instances. Tell me if I'm wrong: there could
be as many as twenty different shapes on the screen at any time, and they
will all have different states. Some will be colored, some not, some will
be of different sizes than the others, and all will contain some kind of
text data too.

Do you know where I can find information of the type that would be in Design
Patterns on this issue on the internet? I am also going to google for such
information right now, but I find that sometimes people already have in mind
a place to go that would take me a long time to find sorting through google
searches. I will go out and look for the book, but I also need some kind of
solution to the issue in the near term.
 
V

Victor Bazarov

Aguilar, James wrote:
[snip]


OK, so there's no language construct that lets me do that. The second best
idea is a HashMap, I guess, with the string and the class. However, as you
said, there is no way to represent simply a type in C++. So what should I
put as the data in the hashmap? A pointer to a constructor? I don't think
that works, does it? So, a pointer to a static member method? Something
like this:

//In Something.h [...]

That code would work, right? (Something::initThis)(int n) would resolve to
a pointer to that method, unless I've got my syntax wrong. Please correct
me if I don't have it right.

That's all fine. The problem is that as soon as you need to do the real
work, you will realise that suddenly all types have to be derived from
that 'Something' class, and that all their "factory methods" (yes, that's
what it's called, it's an idiom) should return the same base pointer and
accept the same arguments. Can your fifty classes handle that? If yes,
good. If not, you will have to do more dancing around to allow your code
to go through the same needle eye to be instantiated.

Go ahead and implement a simple instantiation mechanism for mere two
classes, and you will see what I mean. Then add the third class. If you
do it right, you won't have to do anything except extending the part where
you fill up that HashMap (or whatever).

V
 
P

Phlip

Well, I'm pretty sure I need instances. Tell me if I'm wrong: there could
be as many as twenty different shapes on the screen at any time, and they
will all have different states. Some will be colored, some not, some will
be of different sizes than the others, and all will contain some kind of
text data too.

To solve your outer problem, I would use a Tk Canvas. You might find a
wrapper for it in C++, or you might use a more programmer-friendly language,
like Ruby or TCL, to drive the canvas.

It does what you need out of the box: Float a bunch of shapes around the
screen. Each shape is an object, so changing its attributes intelligently
updates the screen.
Do you know where I can find information of the type that would be in Design
Patterns on this issue on the internet? I am also going to google for such
information right now, but I find that sometimes people already have in mind
a place to go that would take me a long time to find sorting through google
searches. I will go out and look for the book, but I also need some kind of
solution to the issue in the near term.

I Googled for "stl map c++ factory" without the quotes, and got these on the
first page:

http://www.linuxjournal.com/article.php?sid=3687

---8<----------------

Autoregistration
Loading the maker functions into an array associates a position in the array
with each maker. While this may be useful in some cases, we can obtain more
flexibility using an associative array to hold the makers. The Standard
Template Library (STL) map class works well for this, as we can then assign
key values to the makers and access them via these values. For example, we
may desire to assign string names to each class and use these names to
invoke the appropriate maker. In this case, we can create a map such as
this:


typedef shape *maker_ptr();
map <string, maker_ptr> factory;
Now when we want to create a particular shape, we can invoke the proper
maker using the shape name:

shape *my_shape = factory[
We can extend this technique to make it even more flexible. Rather than
loading the class makers in and explicitly assigning a key value to them,
why not let the class designers do the work for us? Using a little bit of
ingenuity, we can have the makers register themselves with the factory
automatically, using whatever key value the class designer chooses. (There
are a couple of warnings here. The key must be of the same type as all the
other keys, and the key value must be unique.)
One way to accomplish this would be to include a function in each shape
library that registers the maker for us, and then call this function every
time we open a shape library. (According to the dlopen man page, if your
library exports a function called _init, this function will be executed when
the library is opened. This may seem to be the ideal place to register our
maker, but currently the mechanism is broken on Linux systems. The problem
is a conflict with a standard linker object file, crt.o, which exports a
function called _init.) As long as we are consistent with the name of this
function, the mechanism works well. I prefer to forego that approach in
favor of one that will register the maker simply by opening the library.
This approach is known as ``self-registering objects'' and was introduced by
Jim Beveridge (see Resources).

We can create a proxy class used solely to register our maker. The
registration occurs in the constructor for the class, so we need to create
only one instance of the proxy class to register the maker. The prototype
for the class is as follows:


class proxy {
public:
proxy(){
factory["shape name"] = maker;
}
};
Here, we assume factory is a global map exported by the main program. Using
gcc/egcs, we would be required to link with the rdynamic option to force the
main program to export its symbols to the libraries loaded with dlopen.
Next, we declare one instance of the proxy:


proxy p;
Now when we open the library, we pass the RTLD_NOW flag to dlopen, causing p
to be instantiated, thus registering our maker. If we want to create a
circle, we invoke the circle maker like so:

shape *my_circle = factory["circle"];
The autoregistration process is powerful because it allows us to design the
main program without having explicit knowledge of the classes we will
support. For instance, after the main program dynamically loads any shape
libraries, it could create a shape selection menu using all the keys
registered in the factory. Now the user can select ``circle'' from a menu
list, and the program will associate that selection with the proper maker.
The main program does not need any information about the circle class as
long as the class supports the shape API and its maker is properly defined.
----8<------------------

You need to give a prototypical shape a "clone()" method, then put a
prototype into each slot in a map, forming a factory. Any C++ tutorial
should cover clonables.
 
A

Aguilar, James

Phlip said:
Aguilar, James wrote:

To solve your outer problem, I would use a Tk Canvas. You might find a
wrapper for it in C++, or you might use a more programmer-friendly language,
like Ruby or TCL, to drive the canvas.

It does what you need out of the box: Float a bunch of shapes around the
screen. Each shape is an object, so changing its attributes intelligently
updates the screen.

Hahaha, I'm sorry for being confusing. I'm not actually using shapes, that
was just an example. I'm actually trying to design a well typed, object
oriented roguelike game. It is something of a toy project, except for
actually defining the behavior of the game, and some issues of pathing and
map making. Of course, it makes it easier that I don't plan to publish the
game unless I make a lot more progress in the 1.5 months before school
starts than I believe I will now. The issue at hand, in any case, was the
vast numbers of monsters and items that will have to be created, some
randomly, and some from save files.

I think I decided once I realized that you could serialize C++ objects that
I was going to use that method for saving things. However, random monster
generation still needed to be looked into.

That article you sent was interesting and useful. I had thought about
making some static method that would cascade up the class heirarchy, but
this is a better solution, especially since the class heirarchy in my case
could be some three or four layers deep (assuming I get that far).
 
P

Phlip

Phlip wrote:

Hahaha, I'm sorry for being confusing. I'm not actually using shapes, that
was just an example. I'm actually trying to design a well typed, object
oriented roguelike game. It is something of a toy project, except for
actually defining the behavior of the game, and some issues of pathing and
map making. Of course, it makes it easier that I don't plan to publish the
game unless I make a lot more progress in the 1.5 months before school
starts than I believe I will now. The issue at hand, in any case, was the
vast numbers of monsters and items that will have to be created, some
randomly, and some from save files.

Hahaha one of my background projects is a game canvas for rogue-like games,
using the TkCanvas. In Ruby.

Writing entire apps in other languages will make you a better programmer,
including a better C++ programmer.
That article you sent was interesting and useful. I had thought about
making some static method that would cascade up the class heirarchy, but
this is a better solution, especially since the class heirarchy in my case
could be some three or four layers deep (assuming I get that far).

Why are you generating zillions of classes instead of zillions of objects?

The last time I finished a rogue-like game, I gave each monster a pointer to
a function called "brain". That permitted me to change monstrous behavior
without creating a zillion different monster classes.
 
A

Aguilar, James

Phlip said:
Hahaha one of my background projects is a game canvas for rogue-like games,
using the TkCanvas. In Ruby.

Writing entire apps in other languages will make you a better programmer,
including a better C++ programmer.

Oh, I think I understand that. This is my first non-trivial app in C++.
I've only been working on the language for about three weeks, so it might
not go well, on the other hand, I am familiar with OO design, since I've
been trained in Java for the past year (my freshman year at college).
However, this will be the first large app I have ever done in any language.
Why are you generating zillions of classes instead of zillions of objects?

The last time I finished a rogue-like game, I gave each monster a pointer to
a function called "brain". That permitted me to change monstrous behavior
without creating a zillion different monster classes.

Well, monsters will have pointers to brains, however, my design is going to
closely follow Nethack's. That means that most of my monsters will be
special cases. Almost all monsters will do something special. For
instance, green slimes will be able to add a SlimeDeath event to the
GeneralEventQueue, but Geletanous cubes will be able to have a consume item
effect on the DungeonFeature directly below them. Meanwhile, brown slimes
will be able to add a BurnEffect to you if you hit them, and blue slimes
will be able to add a FreezeEffect in the same circumstances.

Different monsters will have different random chances of starting off with
particular sets of items (every monster in the game will have an inventory,
though it will in most cases be empty or almost). Also I want some way to
do what Nethack does with cockatrices (they can stone you by various means),
and other types of very unique monsters that can have myriad and unexpected
effects on the player. To do this, I think I need a class structure.
Nethack does it innumerable cascades of if statements, but I think I can
make it neat by classifying all the different things that can possibly
happen, without too much code bloat, and a definite increase in readability.

[OT]
I know that discussing the actual class structure is off topic here, but I'm
going to do it anyway. There will be three or four main base classes
(DungeonFeature, which includes Monster, Item, and GeographicFeature),
Effect (including Healing, Burning, Freezing, Stoning, etc.), Event
(MonsterTurn, all timers, etc.), and a small number of utility classes for
making everything work together (including the main driver, the MapGrid, the
TermInterface, EventQueue, GlobalData, etc.). In this paradigm, I think
that, rather than special casing the types of monsters that would have
special attributes associated, it would be easier just to make a new type
for every _type_ of monster and have monsters that have no special
functionality inherit everything but their stats from their superclass.
[/OT]

Once again, thanks for the advice.
 
P

Phlip

Oh, I think I understand that. This is my first non-trivial app in C++.
I've only been working on the language for about three weeks, so it might
not go well, on the other hand, I am familiar with OO design, since I've
been trained in Java for the past year (my freshman year at college).
However, this will be the first large app I have ever done in any
language.

Get the source to the original rogue. It will send a C or C++ purist into a
frenzy of vomitting.

For example, because monsters are the same as treasure, and only differ by
behavior, the code uses

struct thing {...};
#define monster thing

The code is full of miracles like that.
Well, monsters will have pointers to brains, however, my design is going to
closely follow Nethack's. That means that most of my monsters will be
special cases. Almost all monsters will do something special. For
instance, green slimes will be able to add a SlimeDeath event to the
GeneralEventQueue, but Geletanous cubes will be able to have a consume item
effect on the DungeonFeature directly below them. Meanwhile, brown slimes
will be able to add a BurnEffect to you if you hit them, and blue slimes
will be able to add a FreezeEffect in the same circumstances.

Right. Each of those things is a stateless behavior, with a preCondition()
check and an Effect(Thing & target). So a generic monster is just a list of
the Flyweight behaviors.
Different monsters will have different random chances of starting off with
particular sets of items (every monster in the game will have an inventory,
though it will in most cases be empty or almost). Also I want some way to
do what Nethack does with cockatrices (they can stone you by various
means),

Will they stone you when you're try'na be so good?
and other types of very unique monsters that can have myriad and unexpected
effects on the player. To do this, I think I need a class structure.
Nethack does it innumerable cascades of if statements, but I think I can
make it neat by classifying all the different things that can possibly
happen, without too much code bloat, and a definite increase in readability.

[OT]
I know that discussing the actual class structure is off topic here

No it most certainly is f---ing not. All the flaming you see is due to the
"I have a C++ compiler on my computer. How do I tie my shoes?" questions.

, but I'm
going to do it anyway. There will be three or four main base classes
(DungeonFeature, which includes Monster, Item, and GeographicFeature),
Effect (including Healing, Burning, Freezing, Stoning, etc.), Event
(MonsterTurn, all timers, etc.), and a small number of utility classes for
making everything work together (including the main driver, the MapGrid, the
TermInterface, EventQueue, GlobalData, etc.). In this paradigm, I think
that, rather than special casing the types of monsters that would have
special attributes associated, it would be easier just to make a new type
for every _type_ of monster and have monsters that have no special
functionality inherit everything but their stats from their superclass.
[/OT]

You are going to have to read Design Patterns first. And design the
behaviors first, before designing the structure. A structure, such as a
class hierarchy, is just a system to store behaviors.
 
A

Aguilar, James

Phlip said:
Aguilar, James wrote:

For example, because monsters are the same as treasure, and only differ by
behavior, the code uses

struct thing {...};
#define monster thing

The code is full of miracles like that.

Actually, that was my primary motivation for starting this project instead
of some other experiment. I wanted to see if a Roguelike could be done by
sending _all_ non-standard code into one class and putting everything else
in a clean, understandable class heirarchy.
Right. Each of those things is a stateless behavior, with a preCondition()
check and an Effect(Thing & target). So a generic monster is just a list of
the Flyweight behaviors.

That's true. I'll have to think more about what I want, and then see if I
can do it with a generic monster. I think most of the features of all
monsters will be generic, but some might have non-standard features that
require more than just behaviors to get the job done.
Will they stone you when you're try'na be so good?

Hahaha, almost certainly. But, the way I see it, the world has enough
rogue-like games to get by, so if I'm gonna do anything, I should try to do
something that's never been seen before. Especially since it's really just
an experiment to see what I can make the language do.
No it most certainly is f---ing not. All the flaming you see is due to the
"I have a C++ compiler on my computer. How do I tie my shoes?" questions.

Hahahaha! That totally describes my state exactly five weeks ago, when I
was starting to teach myself C. I was like, "whut is a makefile? h0w do i
liNk things? .o?" I think I'm a little better off now, but I will say that
using an IDE during my first two CS courses really hurt my understanding of
what was going on inside the computer during the translation of a program.
I think I'm a lot closer to that now, but I still have a long way to go.
Two of the biggest areas I can stand to improve in are knowledge of the STL,
and knowledge of design patterns, which brings us to your next point:
You are going to have to read Design Patterns first. And design the
behaviors first, before designing the structure. A structure, such as a
class hierarchy, is just a system to store behaviors.

Since everyone is talking about this Design Patterns book, I'm gonna look it
up online and try to purchase it tomorrow morning. As for designing
behaviors first, I'm not sure I get what you mean by that. Do you mean
design monster behaviors first, or the behavior of the game? I think you're
talking about the latter, so here's my answer. I have some general idea of
how I want the game to work just by seeing what I like in other Roguelike
games. I consider myself to my current design to be in phase .1:

Analysis: An easily extensible, readable, and customizable roguelike game
written in the Object oriented paradigm, supporting (at least) everything
that Nethack and ADOM can do.

Design: (that's now -- I'm finding classes that will support my goal.
Really, what I'm doing so far is not actually coding at all, but just
writing general contracts for each of my classes and seeing what kind of
information they'll need. Each class I finish reveals to me several more
that I will need. For instance, at first, I though that I would only need
Effects to describe all things that a monster can do to itself or anything
else. Then I realized that there would be no easy way to do timed effects
without some kind of notion of event. This revealed to me the way I was
going to design the turn system, etc. The only thing in even semi-working
order is the class that controls writing information to the terminal and
getting information from the user.)

Implementation: I'll get back to you in a couple of months on this one. As
fast as I'd like to think I write, it's going to take a while to write this
thing.(for instance, today, I stopped after I got frustrated trying to look
up information on priority_queue, which will be important for my EventQueue
data structure).

Anyway, I will definitely get that book. Also, I'm really enjoying this
discussion. Thanks for all the advice. This is by far the best
conversation I've ever had on usenet.

James
 
U

Uwe Schnitker

Phlip said:
Aguilar, James wrote:
SNIP>

You are going to have to read Design Patterns first. And design the
behaviors first, before designing the structure. A structure, such as a
class hierarchy, is just a system to store behaviors.

Hey, Phlip, what kind of advice is that?

Whatever happened to TDD?

Do you really value "read Design Patterns first" over "write tests first"?

Surely you can do better?

NOI,

have fun,

Uwe
 
P

Phlip

Uwe said:
Phlip wrote:

Hey, Phlip, what kind of advice is that?

Whatever happened to TDD?

Do you really value "read Design Patterns first" over "write tests first"?

Surely you can do better?

Nope. One Josh Kerievsky beat me to it. Read /Refactoring to Patterns/
first. Then TDD. Then document the patterns that emerge, and nudge the few
that should have.
 
U

Uwe Schnitker

Phlip said:
Nope. One Josh Kerievsky beat me to it. Read /Refactoring to Patterns/
first. Then TDD.

I wasn't referring to the book TDD, but to the technique.
 
U

Uwe Schnitker

Phlip said:
Nope. One Josh Kerievsky beat me to it. Read /Refactoring to Patterns/
first. Then TDD.

I wasn't referring to the book TDD, but to the technique.
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top