hey guys, it's been a while since i've worked on any code since work and life is a nightmare atm.
so lets cut to the chase.
now, i'm a complete noob when it comes to implementing code spread across separate headers and source files
and i've been so baffled by my code i've dissected it into nothing useful. Since it's such a nightmare currently I won't be able to provide you with snippets of what it looks like.
but basically, i've been trying to figure out how to point a class in my "CMenu.h" and "CMenu.cpp" file, to the irrlicht device, scene manager, gui environment etc.
and i've been having no luck with having it refer to the actual devices, causing it to just fail on runtime.
if anyone knows a super easy way to point to these things, or a way to avoid cross-source referencing like that, i'd probably be overjoyed.
now this is obvious that i'm quite poor when it comes to knowing how to fully use C++, so if theres any basic tutorials that anyone could link that would flat out save my hide ( I really don't know what i'd be looking for, i've tried looking at pointers, extern functions variables etc etc, which i've got working, but not for the real meaty irrlicht devices and managers )
tldr; if you guys know how one would go about working with separate source files in irrlicht, i'd love you guys to give me a couple of pointers or a little 101 on it, i'm nearly completely in the dark about such things.
Cheers, prod
Referring to scenemanager, separate source files
Re: Referring to scenemanager, separate source files
You can take a look at "Demo" in the Irrlicht examples.
Some general infos which might help (ask if one of them doesn't make sense):
Each .cpp file is compiled on it's own.
The compiler always works from the top of the file to the bottom.
Include files are copy-pasted in a pre-compile-step into the places of corresponding #include lines.
The result of compiling is one .o (or .obj on Windows) file per .c/.cpp file.
In each line the compiler needs to know all types used in this line.
The main reason why the compiler needs the type information is that it needs to know which size a type has.
Therefore - every type declaration (classes, structs, typedef's) has to be done before a type is used for the first time.
That's why types are usually in headers which you include first.
Because your compilers need to know the size of any type it is impossible (!) to have 2 types using each other directly. Impossible because each needs to know the size of the other to calculate it's own size. In that case you have to work with pointers (or references) - as those have all the same size (32 bit or 64 bit depending on your system) and so the compiler knows how big they are. The compiler still needs to know the type first (for figuring out type-errors) - which is why you use forward declarations in that case to tell it about the type of that pointer.
Classes are basically stamps. To use them you stamp their size into memory. That's called instancing and the result of this is an object in memory. That object takes a fixed amount of bytes of your memory cells (that's why the compiler needs to know the exact size of all types before it can use it). Variable names etc are just comfort for the programmer - the compiler doesn't care so much (it only wants to know type-names and type-sizes before any line that uses them).
Pointers are also a type. So if you have MyClass and MyClass* you should really think of them as 2 different types - the first can have any size while the pointer will probably be 32 bit or 64 bit (exactly enough for a number that's large enough to address the memory on your system). So if you see any pointer type think of it just as type like int or char or whatever as first step. But they have a speciality - they are mostly used to not just contain a number but the number has a special meaning - it's an address in memory. Usually the address of an object.
The trick to having several files is - you write class declarations which have enough information in them so the compiler can figure out the size of that class. If you have to use another class where the compiler doesn't know the size yet at that point then you have to use a pointer (or reference).
You put class declarations into headers.
Each header also has an include guard (that ifndef stuff which starts each header). Those prevent that classes are declared several times if a header is included several times by a .cpp file. That would happen for example when you include two headers which again both include the same 3rd header.
So that's what you need to know for compiling - check a few headers for examples (whole Irrrlicht include folder is full of headers).
At runtime you have to ensure classes are instanced (put into memory). You are only working with objects.
There are 2 types of memory - stack and heap - learn the difference. One of the main things to remember is that objects in stack memory are removed from memory as soon as the scope in which they are put on the stack ends (or at least you should think that way - internally it's slightly more tricky as the memory is not really cleared but just given free so that it will be overwritten soon). End of scope is mostly the } bracket (but read up on scopes in c++, it's very essential and you can get really hard to find errors if you don't understand that part).
If you want to pass an object around you usually do not copy it, but you have only one instance and then tell other classes where that object is by copying them a pointer-variable which contains the address of that object. Exception are small types like int, char, float, etc... those are smaller or the same size as a pointer, so often you copy their values. Though you still should have a single point in your code (typically a class in c++) that's responsible for the real value - and copies are then just passed with getter functions.
You have to be aware at all times:
- Who creates the object
- Who deletes the object (good design is usually that the same class creates and destroys an object).
- Who has pointers to the objects (Irrrlicht grab() drop() mechanism is for that for example).
- Be aware when copying pointers to other classes how long that object will be in memory (remember stack variables are destroyed at the end of scope - passing addresses to memory that will be destroyed in a moment is a very bad idea!).
- To make it easier for yourself - always, always(!!!) initialize _all_ your pointers with 0. For member-variables in classes you do that typically in the initalizer list of the constructors. This allows you to check if a pointer is initialized correctly at runtime (and you also see it in the debugger).
OK, that was a wild mix of hints... hope one or the other is of use ;-)
Some general infos which might help (ask if one of them doesn't make sense):
Each .cpp file is compiled on it's own.
The compiler always works from the top of the file to the bottom.
Include files are copy-pasted in a pre-compile-step into the places of corresponding #include lines.
The result of compiling is one .o (or .obj on Windows) file per .c/.cpp file.
In each line the compiler needs to know all types used in this line.
The main reason why the compiler needs the type information is that it needs to know which size a type has.
Therefore - every type declaration (classes, structs, typedef's) has to be done before a type is used for the first time.
That's why types are usually in headers which you include first.
Because your compilers need to know the size of any type it is impossible (!) to have 2 types using each other directly. Impossible because each needs to know the size of the other to calculate it's own size. In that case you have to work with pointers (or references) - as those have all the same size (32 bit or 64 bit depending on your system) and so the compiler knows how big they are. The compiler still needs to know the type first (for figuring out type-errors) - which is why you use forward declarations in that case to tell it about the type of that pointer.
Classes are basically stamps. To use them you stamp their size into memory. That's called instancing and the result of this is an object in memory. That object takes a fixed amount of bytes of your memory cells (that's why the compiler needs to know the exact size of all types before it can use it). Variable names etc are just comfort for the programmer - the compiler doesn't care so much (it only wants to know type-names and type-sizes before any line that uses them).
Pointers are also a type. So if you have MyClass and MyClass* you should really think of them as 2 different types - the first can have any size while the pointer will probably be 32 bit or 64 bit (exactly enough for a number that's large enough to address the memory on your system). So if you see any pointer type think of it just as type like int or char or whatever as first step. But they have a speciality - they are mostly used to not just contain a number but the number has a special meaning - it's an address in memory. Usually the address of an object.
The trick to having several files is - you write class declarations which have enough information in them so the compiler can figure out the size of that class. If you have to use another class where the compiler doesn't know the size yet at that point then you have to use a pointer (or reference).
You put class declarations into headers.
Each header also has an include guard (that ifndef stuff which starts each header). Those prevent that classes are declared several times if a header is included several times by a .cpp file. That would happen for example when you include two headers which again both include the same 3rd header.
So that's what you need to know for compiling - check a few headers for examples (whole Irrrlicht include folder is full of headers).
At runtime you have to ensure classes are instanced (put into memory). You are only working with objects.
There are 2 types of memory - stack and heap - learn the difference. One of the main things to remember is that objects in stack memory are removed from memory as soon as the scope in which they are put on the stack ends (or at least you should think that way - internally it's slightly more tricky as the memory is not really cleared but just given free so that it will be overwritten soon). End of scope is mostly the } bracket (but read up on scopes in c++, it's very essential and you can get really hard to find errors if you don't understand that part).
If you want to pass an object around you usually do not copy it, but you have only one instance and then tell other classes where that object is by copying them a pointer-variable which contains the address of that object. Exception are small types like int, char, float, etc... those are smaller or the same size as a pointer, so often you copy their values. Though you still should have a single point in your code (typically a class in c++) that's responsible for the real value - and copies are then just passed with getter functions.
You have to be aware at all times:
- Who creates the object
- Who deletes the object (good design is usually that the same class creates and destroys an object).
- Who has pointers to the objects (Irrrlicht grab() drop() mechanism is for that for example).
- Be aware when copying pointers to other classes how long that object will be in memory (remember stack variables are destroyed at the end of scope - passing addresses to memory that will be destroyed in a moment is a very bad idea!).
- To make it easier for yourself - always, always(!!!) initialize _all_ your pointers with 0. For member-variables in classes you do that typically in the initalizer list of the constructors. This allows you to check if a pointer is initialized correctly at runtime (and you also see it in the debugger).
OK, that was a wild mix of hints... hope one or the other is of use ;-)
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
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Referring to scenemanager, separate source files
woah, that's a long reply, and this is.. very handy wow. thanks for taking the time to write all that out, will keep these hints around. cheers!