How to create and store instances of a class at runtime Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

How to create and store instances of a class at runtime

Post by Cheo »

Hi all

I'm doing a tiny project with the intention to learn how to store instances of a class created by the end user at runtime.

This project has a frame and a dialog. The frame set the values of the class instance and creates it. The dialog prints in screen the information of the objects.

This is the class declaration in a header file:

Code: Select all

#include <wx/dynarray.h>

#ifndef FILE_WITH_CLASS_DEFINITION_H
#define FILE_WITH_CLASS_DEFINITION_H

class Hero;
WX_DECLARE_OBJARRAY(Hero, ArrayOfHeroes);

class Hero {
    public:
        int m_Strength;
        int m_Intelligence;
        int m_Dexterity;
        int m_Endurance;
        int m_Personality;
        wxString m_Name;

        ArrayOfHeroes m_Heroes;

        Hero(wxString name, int strength, int intelligence,
            int dexterity, int endurance, int personality);

        int Health();
        int Mana();
};

Hero::Hero(wxString name, int strength, int intelligence, int dexterity,
            int endurance, int personality) {
    m_Name = name;
    m_Strength = strength;
    m_Intelligence = intelligence;
    m_Dexterity = dexterity;
    m_Endurance = endurance;
    m_Personality = personality;
}

int Hero::Health() {
    return m_Strength * m_Endurance;
}

int Hero::Mana() {
    return m_Intelligence * m_Personality;
}

#endif
In the frame source code, I have:

Code: Select all

#include <wx/arrimpl.cpp>

... some code here

WX_DEFINE_OBJARRAY(ArrayOfHeroes);

... some code here
... etc
Everything works perfect. The end user uses five spin control to set the values of the strength, intelligence, dexterity, endurance and personality. Then, s/he presses a button and the object is created and stored in a vector (well, a wxwidget's array of objects). It's at this stage where I'm stuck. How do I store the instance in the vector?

Any help will be appreciated. If you need more of the code of the frame, tell me and I'll post it.
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

Usually I use std::containers (vector,list,map) instead of wxArrays,
but its pretty much the same way to implement a class for this.
You also need to implement a copyconstructor for your class,
also a destructor and a op= are sometimes usefull.

For Adding your class to the array, simply call
array.Add(instance);
http://wxwidgets.org/manuals/2.6.3/wx_w ... wxarrayadd

phlox
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

Hi,

You are creating an array of class Hero, but then holding an instance of this array in each member of the class. I don't think that's likely to be what you want.

I suggest you create a new class, called (say) HeroManager. This will do things like create new heros, load and save the list of heros; and this is where you'll put ArrayOfHeroes m_Heroes;. At the beginning of the program, you'll create a single instance of HeroManager, manager.

When manager creates a new Hero, it will do as phlox81 said:
m_Heroes.Add( new Hero( wxT("David", 100, 1, ...) );

Regards,

David
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

Ok, now I've added this new class declaration into the header file:

Code: Select all

class HeroManager;
WX_DECLARE_OBJARRAY(HeroManager, ArrayOfHeroes);

class HeroManager {
    public:
        ArrayOfHeroes m_Heroes;
};
As you see, I moved the object array from Hero class to HeroManager class. Then, in the source code, I create a new instance of HeroManager:

Code: Select all

HeroManager manager;
And then... well... that's it. I don't know what else to do.
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

And then... well... that's it. I don't know what else to do.
Well, you do whatever you were doing before, when you said:
This project has a frame and a dialog. The frame set the values of the class instance and creates it. The dialog prints in screen the information of the objects.
When the app starts, you get the frame tol create an instance of HeroManager, and call its Load() method to load previous heroes (from the wxConfig where you carefully stored them, pickled, laid end to end... ;) ). You'll presumably then have a dialog that lets the user Add, Run etc.

If the choice is Add, that button-handler will call manager.CreateNew(), which will call your previous dialog to create a new hero, then add him to the array. Either then or when the app exits, you'll save the contents of m_Heroes to the wxConfig file.
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

When the app starts, you get the frame tol create an instance of HeroManager, and call its Load() method to load previous heroes (from the wxConfig where you carefully stored them, pickled, laid end to end... ;) ). You'll presumably then have a dialog that lets the user Add, Run etc.

If the choice is Add, that button-handler will call manager.CreateNew(), which will call your previous dialog to create a new hero, then add him to the array. Either then or when the app exits, you'll save the contents of m_Heroes to the wxConfig file.
Thanks, David.

Wow, that makes a lot of sense, but at the moment is beyond my knowledge. When I said I didn't know what else to do, I meant I didn't know how to implement the array of objects to store the instance. I coded:

Code: Select all

m_Heroes.Add(new Hero(name, strength, intelligence, dexterity, endurance, personality));
but, doesn't compile: 'm_Heroes' undeclared (first use of this function)

I tried:

Code: Select all

manager.m_Heroes.Add(new Hero(name, strength, intelligence, dexterity, endurance, personality));
and different combinations (because I have no a clue).

I fail to implement the actual algorithm to store the instance.
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

Ah, I see what you mean.

I normally use WX_DEFINE_ARRAY to store pointers, rather than WX_DECLARE_OBJARRAY which stores objects. But I think you need to do:
Hero myHero(name, strength, intelligence, dexterity, endurance, personality);
manager.m_Heroes.Add( myHero );
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

phlox81 wrote:Usually I use std::containers (vector,list,map) instead of wxArrays,
but its pretty much the same way to implement a class for this.
How is that? I cannot use STL vectors within wxWidgets projects.
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

DavidHart wrote:Ah, I see what you mean.

I normally use WX_DEFINE_ARRAY to store pointers, rather than WX_DECLARE_OBJARRAY which stores objects. But I think you need to do:
Hero myHero(name, strength, intelligence, dexterity, endurance, personality);
manager.m_Heroes.Add( myHero );
I've tried that also, but with no luck. Thanks anyway.
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

What error message does it produce?
loptr
Earned some good credits
Earned some good credits
Posts: 110
Joined: Tue Jan 23, 2007 12:22 pm
Location: Kiel, Germany
Contact:

Post by loptr »

don't know if this might help you, but how about using template classes? you'll only have to write that template once and then you can store whatever you want in it, in whatever project you want ;)

could go somewhat like this:

Code: Select all

template <class T>
class Node {
    private:
        //ATTRIBUTES
            //= following Node
            Node<T>* next;
            //= preceding Node. this will be NULL for the initial Node if chosing non-circular list
            Node<T>* prev;
            //= the actual data object
            T* data;

    public:
        //FUNCTIONS
            //constructors and destructors
                //= Default constructor
                Node() { data=NULL; next=NULL; prev=NULL; }
                //=============================================================
                // Default constructor. initialises the Node with the submitted data
                // @param sData the data-containing object of the newly created Node
                //=============================================================
                Node(T* sData);
                //= Default destructor.
                ~Node() {}

            //accessing
                //=============================================================
                // sets the next-pointer to the Node that contains the next data-object
                // @param sData the data-containing object to add to the list
                //=============================================================
                void SetNext(Node<T>* sNode) { next=sNode; }
                //= returns the next Node in the list
                Node<T>* GetNext() { return next; }
                //=============================================================
                // sets the prev-pointer to the Node that contains the previous data-object
                // @param sData the data-containing object to add to the list
                //=============================================================
                void SetPrev(Node<T>* sNode) { prev=sNode; }
                //= returns the previous Node in the list
                Node<T>* GetPrev() { return prev; }
                //= returns true if Node has a successor, false otherwise
                bool HasNext() { return (next!=NULL ? true : false); }
                //= returns true if Node has an antecedent, false otherwise
                bool HasPrev() { return (prev!=NULL ? true : false); }
                //= returns the data as pointer to the object used in this list
                T* GetData() { return data; }

            //processing
                //=============================================================
                // adds a new Node to the list
                // @param sData the data to add
                //=============================================================
                void Add(T* sData);
                //= deletes last node
                void DeleteLast();
                //= deletes the complete list after the calling Node
                void DeleteList();
                
                /* possibly more functions here */
                
};//template class
what you basically do here is just to implement a class that is managed like a linked list (that you could even configure to be circular).

to use this as a store you just declare:

Code: Select all

Node<Hero>* m_heroes=new Node<Hero>( /* your params here */);
that way you initialize the headNode with the first data object (there are far more complex structures possible, e.g. with different types of nodes, but this is just to show the idea...)

then you can manage your heroes as you want. basically it's only constructing nodes for the list, each one being able to store an arbitrary data object (int, bool, wxDialog, Hero etc.)

of course, you might be obliged to add custom functions, but here presented is only an example, not fully functional code... (and, btw, it is not mandatory to use pointers...)
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

DavidHart wrote:What error message does it produce?


HeroeFrm.cpp: In member function `void HeroeFrm::WxButton1Click6(wxCommandEvent&)':
HeroeFrm.cpp:280: error: no matching function for call to `ArrayOfHeroes::Add(Hero&)'
HeroeFrm.cpp:60: note: candidates are: void ArrayOfHeroes::Add(const _wxObjArrayArrayOfHeroes&, size_t)
FileWithClassDefinitions.h:47: note: void ArrayOfHeroes::Add(const _wxObjArrayArrayOfHeroes*)
Cheo
Knows some wx things
Knows some wx things
Posts: 39
Joined: Mon Jan 01, 2007 3:45 pm

Post by Cheo »

loptr wrote:don't know if this might help you, but how about using template classes? you'll only have to write that template once and then you can store whatever you want in it, in whatever project you want ;)
:shock: My God. I've heard about templates before, but I'm still struggling with simple classes. I'll give it a look anyway. Thanks.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

Cheo wrote:
loptr wrote:don't know if this might help you, but how about using template classes? you'll only have to write that template once and then you can store whatever you want in it, in whatever project you want ;)
:shock: My God. I've heard about templates before, but I'm still struggling with simple classes. I'll give it a look anyway. Thanks.
Well for these kinds of things i usually use simply std::vector.

e.g.

std::vector<Hero> heroes;
...
heroes.push_back( Hero(name,etc...) );

there are also wxWidgets classes that act similarly, and many other ways to do it

this is a way to use templates that will not actually require you to write them. You should probably play around with vectors and/or similar stuff a bit to get used to how it works, perhaps just by storing ints in it at first - you seem a bit confused now,. ithink it would help a lot to just do simple stuff and get used to the way it works before trying to make an actual game
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

Cheo wrote:
phlox81 wrote:Usually I use std::containers (vector,list,map) instead of wxArrays,
but its pretty much the same way to implement a class for this.
How is that? I cannot use STL vectors within wxWidgets projects.
Sure you can. I do that every day.
You cannot add them to the Widgets, but you can't do that eather with the wxObjArray.
The STL offers a lot of algorithms and accessiterators for its containers,
which makes me favor them.
Post Reply