Some C++ Class questions...

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Some C++ Class questions...

Post by christianclavet »

Hi..

I would like to use a class like a container for variables.

I've started it like this:

Code: Select all

class Gameinfo 
{
      public :
      // Global variables contained in this information object.
      IrrlichtDevice *device;
      scene::ISceneManager *smgr;
      video::IVideoDriver *driver;
      scene::ICameraSceneNode *camera;
     SIrrlichtCreationParameters param; 
Then in my main() use this:

Code: Select all

main()
Gameinfo game; // retrieve the gameinformations class
   game.device=0;
    game.device=createDeviceEx(game.param); 
Seem that variables defined with pointer reference (*) do not work. Still newbie with this. What I am doing wrong?

Would I have to define them global instead and put them in namespaces? My idea of using classes is that a defined variable will have to be named using the class. So there much less chances of having errors. The variables will be isolated inside the class and only accessible by calling it by the class.

Variable without pointer definitions work correctly, assigned values can be retrieved. (Like game.param)

Any advice?
Last edited by christianclavet on Mon Dec 10, 2007 9:50 pm, edited 1 time in total.
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

They should work just like pointers. Right now they're not pointing to anything:

game.device = createDevice(driverType, core::dimension2d<s32>(640, 480));

game.device->do something();
Last edited by fireside on Mon Dec 10, 2007 9:54 pm, edited 1 time in total.
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

That's strange...

I will have to investigate more in that case.

When I initialise the device it crash. If the device is defined inside main() it work (retrieve the value I put inside game.param correctly)

I'm pretty sure it's something stupid, that I am not seeing at the moment... :oops:
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

All the examples create the device driver inside main, I think you have to do it that way.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Re: Some C++ Class questions...

Post by rogerborg »

Code: Select all

Gameinfo game; // retrieve the gameinformations class
   game.device=0;
    game.device=createDeviceEx(game.param); 
Seem that variables defined with pointer reference (*) do not work.
Do not work in what way? The concept is fine, it's the execution that's lacking.
If the device is defined inside main() it work (retrieve the value I put inside game.param correctly)
OK, that's a bit disturbing. As usual, if you only post a snippet, then we have to guess at what's happening.

What you're doing based on the posted code is declaring a completely new instance of Gameinfo on the stack. You're not "retrieving" anything. The instance of Gameinfo that you create bears no relation to any other instance that you may have created anywhere else, and won't share any data with it.

In fact, in C and C++, stack variables aren't initialised by default; you just get whatever was in the memory that they got allocated to. Some compilers (in debug mode) will assign explicit values, but only to help you catch this error.

So what you're doing is creating a new Gameinfo containing random crap, then passing game.param to createDeviceEx(). You may as well pass rand().

Can you post some more code, or explain more fully what you're trying to do?
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

Thanks Rogerborg and Fireside.

I found out that it was working after all. But I made the mistake of trying to call the class variables inside another class. I think it didnt do it the right way using inheritances. The values where not valid. (runtime error)

With that class for example (added Gameinfo so that it should inherit the class (hope so)):

Code: Select all

class MyEventReceiver : public IEventReceiver, Gameinfo
{ 
      // Event receiver functions
public: 
    int action;
    bool OnEvent(const SEvent& event) 
   { ...
Would I have access to the pointer for device as defined in Gameinfo?:

Code: Select all

class Gameinfo
{
    public :
    IrrlichtDevice *device;
    scene::ISceneManager *smgr;
    scene::ICameraSceneNode *camera; 
    gui::ICursorControl* cursorcontrol;
...

Initialisation of Device is done in the class Gameinfo as function Init(); Param are setup in the class constructor. Init() is called from main() like this

Code: Select all

Gameinfo game;
game.Init();
Here is the Init() function inside the Gameinfo class.

Code: Select all

void Init()
      {
           //device = createDevice(video::EDT_DIRECT3D9);
          device = createDeviceEx(param);
          smgr =  device->getSceneManager();
      }
The Idea, is to have a Gameinfo class that will contain the information about the game (pointers, gamestates). So that almost nothing will be defined directly in main() or other as global. I would want to access via the classes.

If im creating another class for other types of functions (working on a new type of camera now). Can I use this that way:

Code: Select all

Class NCamera 
Public :
void Init()
    { Gameinfo game;
       game.device=...
Or that way: (Should inherit the class Gameinfo and I should have access of it directly?)

Code: Select all

Class NCamera : public Gameinfo
Public :
void Init()
  {device = ...
Or that way?:

Code: Select all

Class NCamera : 
Public :
    Gameinfo game;
    void Init()
       {game.device = ...
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I hope I understood it correctly. You want to use the Gameinfo in another class? Probably you know 99% of the stuff I will write already, but I don't know which percent you are missing - so sorry if this will get long :-)

I think you are mixing up classes and instances (objects) somewhat. Gameinfo is a class definition describing how objects of those type will look like. But once you create real objects (which means really nothing but: reserve a block of memory which is large enough to contain all variables mentioned in a class) and you want to use that data in some other objects you have to pass it to that other object. Doesn't matter if that other object is of the same class or derived from that class or of another class type. You always will have to pass it if you want to access that data.

So to use that data from your variable 'game' you will have to pass it to objects of those classes which want to access it. This means: Add a function to the class which receives the data. You even need to add that function when passing objects of the same class (often that function is the so called copy-constructor). You have several ways to do that, by object, by reference or by pointer . You could call that function "setGameinfo". Or often you will just add a parameter in the constructor and use that to pass the object. Within that function (or constructor) you have now once more the choice what to do. Sometimes you will directly access the data, but here you will probably want to copy the data or keep a pointer or reference to it so you can access it later on. That copy is another variable of the receiving class. Usually you use references or pointers (internally they are the same), because that will save memory and is faster.

As example (using the constructor to pass the data as reference and saving it in the class also as a reference):

Code: Select all

class NCamera
{
    Gameinfo & myReferencetoAGameObject; // reference
    NCamera(Gameinfo &refToAGameInfoObject) :  myReferencetoAGameObject(refToAGameInfoObject) {}
};
And now you can pass your game to any object of NCamera. But you must be careful. The reference will point to that memory which you allocated when you did push your 'game' variable on the stack. So when you created 'game' locally it will be invalid as soon as that local scope is ended. Scope is always from { to }. No problem if you create it within main() - because when main is ended your application is ended. But a big problem if you create 'game' for example in a subfunction.

Just to make the difference between class/object more clear. What would have happened on inheritance? Like your example with "class NCamera : public Gameinfo"?
A class describes just how object will look like in memory. So in this case whenever you create a NCamera object it will not only reserve memoryblocks large enough to contain all variables in NCamera but it will reserve a block large enough to contain memory for all variables in NCamera and in Gameinfo. And you could addionally access all that memory in such objects using the variablenames of NCamera and Gameinfo (except private names of Gameinfo - though you could still access even that memory quite easy with simple tricks). But you could not access any memory allocated for other objects (not even of same type). And the reason for that is that you don't know where those other objects are. Not before you pass that information to the class.

It's very important to understand the way data is hanging around in memory. All that stuff with classes and variables is just there because it helps to avoid a lot of bugs when you do no longer need to access the data using numbers.

edit: Another example. This time we pass a pointer and keep a real copy in the camera. While this is not recommended I wanted to add that because of the differences. Both examples will work (unless I made some typos), but they do different things.

Code: Select all

class NCamera
{
    NCamera() {} // just to show I do nothing here
    Gameinfo myGameObject; // real copy
    void setGameinfo( Gameinfo * info) { myGameObject = *info; }
};
There are several things to note here:
- myGameObject will contain random data, but it will call the constructor of Gameinfo (so it's important to always set all variables to non-random values in the constructor!!!)
- Because a real copy is made you don't have to care if the memory of your Gameinfo object which you pass to NCamera points afterwards still to valid memory. Scopes no longer matter.
- It will use more memory now.
- Gameinfo might still contain data which can get invalid at some time. Even a real copy might cause problems if for example pointers which are within Gameinfo are suddenly invalid (for example because the device was destroyed).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

Thanks CuteAlien.

I'll take the time to read this carefully. You're right. I'm mixing classes and instances and didnt knowed about the & symbol for reference.

I'll check the net for more info about this after reading more what you've written.
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

Pointers can get you in trouble so be careful with them. The less the better as far as I'm concerned. I wish Irrlicht was clearer with it's drop method. Some are recommended to be dropped, some you're not supposed to drop. I can't tell where I'm at with it.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

@fireside: That's described here: http://irrlicht.sourceforge.net/docu/cl ... unted.html

In short: You only call drop() if you either called grab() yourself, if you used new() to create an irrlicht object or if you created the object using an irrlicht function which started with the word "create".
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

Thanks, I didn't see that. That will help.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Re: Some C++ Class questions...

Post by Acki »

just another question, why don't you simply use a struct for this ??? :shock:
you can work withit like with a class !!! ;)

Code: Select all

struct Gameinfo{
      // Global variables contained in this information object.
      IrrlichtDevice *device;
      scene::ISceneManager *smgr;
      video::IVideoDriver *driver;
      scene::ICameraSceneNode *camera;
     SIrrlichtCreationParameters param; 

     // constructor
     Gameinfo(){
         device = 0;
         smgr = 0;
         driver = 0;
         camera = 0;
     }

     // create the device
     bool createDevice(){
         device = blablabla;
         smgr = device->blablabla();
     }
};
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Because a struct with a constructor is a class without private or protected members?
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

fireside wrote:Pointers can get you in trouble so be careful with them. The less the better as far as I'm concerned. I wish Irrlicht was clearer with it's drop method. Some are recommended to be dropped, some you're not supposed to drop. I can't tell where I'm at with it.
Only drop() pointers that are returned from createFoo() methods. If you know of any inconsistencies regarding that, please raise bugs.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
mqrk
Posts: 16
Joined: Mon Dec 10, 2007 5:55 am

Post by mqrk »

Do a search for "Singelton pattern". Basically, you will probably only ever want one instance of your gamedata and can guarantee this programatically and not worry about when it is instantiated.

Basically, you'll want a public static Instance() function and a private static pointer to the instance. When Instance() is called, it checks if the instance has already been created, otherwise it creates it and returns it. Notice that to make this work, the constructor has to be protected so that you don't accidentally create a new instance.

Also, I'm pretty sure that when you declare a pointer, int, float, etc. in a class it is automatically initialized to zero. It is only left uninitialized (garbage) if you declare it in a function.
Post Reply