-
Hi again. I'm going through the SFML tutorial on github.com named "Manage different screens in a game", which can be found here:
https://github.com/SFML/SFML/wiki/TutorialScreens (https://github.com/SFML/SFML/wiki/TutorialScreens)
Would appreciate it if someone can explain how the following code works:
// Screen.hpp
class cScreen
{
public :
virtual int Run (sf::RenderWindow &App) = 0;
};
----------
// Main.cpp
01 #include <fstream>
02 #include <iostream>
03 #include <sfml/Graphics.hpp>
04 #include "screens.hpp" // Includes screen.hpp, screen_0.hpp and screen_1.hpp
05
06 int main(int argc, char** argv)
07 {
08 //Applications variables
09 std::vector<cScreen*> Screens;
10 int screen = 0;
11
12 //Window creation
13 sf::RenderWindow App(sf::VideoMode(640, 480, 32), "SFML Demo 3");
14
15 //Mouse cursor no more visible
16 App.ShowMouseCursor(false);
17
18 //Screens preparations
19 screen_0 s0;
20 Screens.push_back (&s0);
21 screen_1 s1;
22 Screens.push_back (&s1);
23
24 //Main loop
25 while (screen >= 0)
26 {
27 screen = Screens[screen]->Run(App);
28 }
29
30 return EXIT_SUCCESS;
31 }
(For more details on "all" of the code, please refer to the link given.)
Line 09 is: std::vector<cScreen*> Screens;
I understand that it's instantiating a vector named Screens. What I don't understand is how the cScreen* pointer type is used.
The class screen_0 inherits from the class cScreen. Similarly, the class screen_1 inherits from the class cScreen. But the code in screen_0 is different from the code in screen_1. So when line-09 instantiates the Screens vector using <cScreen*>, how does the vector know the size of screen_0 and screen_1 since they are both different sizes?
I assume that when screen_0 and screen_1 are push_back'd into the Screens vector, the vector just logs the starting address of each push_back and the actual size of each element is irrelevant. Is that correct? If so, then why does the "std::vector<cScreen*> Screens" need to know what type of pointer cScreen is? If it's just a memory address that's being logged, why care that the pointer type is cScreen?
Learning C++ so please excuse my noobie question,
Raptor
-
It's polymorphism, you should look that up.
The vector stores the cScreen pointer so that method Run() can be called, because cScreen objects and their derieved objects have that method.
-
The class screen_0 inherits from the class cScreen. Similarly, the class screen_1 inherits from the class cScreen. But the code in screen_0 is different from the code in screen_1. So when line-09 instantiates the Screens vector using <cScreen*>, how does the vector know the size of screen_0 and screen_1 since they are both different sizes?
If so, then why does the "std::vector<cScreen*> Screens" need to know what type of pointer cScreen is? If it's just a memory address that's being logged, why care that the pointer type is cScreen?
In fact you could declare the vector as std::vector<void*> and then you'd be able to pass in any pointer to any class, but it's not adviced to do so.
-
I'm not sure but I think bad(and cool ;D) things happen if you mix void* with polymorhpism like that without many casts:
std::vector<void*> yay;
myclass1 one;//derieved from baseclass which has virtual method ouch()
yay.push_back(&one);//should be static_cast<void*>(static_cast<baseclass*>(&one))
baseclass * ptr =static_cast<baseclass*>(yay[0]);
ptr->ouch();
One of last two lines(I think last) would cause extremely interesting error.
-
Yeah there are nearly no scenarios where void-pointers would make sense and couldn't be replaced by something else, so just don't use it.
My point was more that the size of the class indeed doesn't matter, since a pointer is just a pointer, with the decleration of which class you can catch access violates and all kinds of messy stuff at compile time.
As for the cast, you could use reinterpret_cast<derived*> but that's also very very bad. :D
-
That actually came up in my code while tying something to box2d but could come up when tying box2d and sfml because physical bodies and fixtures(and joints) can hold void* pointer and attempting to cast directly from sprite/text/whatever pointer to void* and then later casting from void* to drawable* and trying to draw it would cause that error.
-
Yeah Box2D's classes aren't that nicely designed, specially the void-pointer thing could've been done a bit better, but with that it was way easier to port it to other platforms/languages.
-
It's polymorphism, you should look that up.
The vector stores the cScreen pointer so that method Run() can be called, because cScreen objects and their derieved objects have that method.
FRex,
Thanks for pointing me in the right direction. I had not gotten to polymorphism yet so had no clue.
With your gentle nudge, I checked all of my C++ books and found that Deitel's "C++ How to Program" gives a great in-depth explanation of exactly what I was asking, in the polymorphism chapter. It has example code similar to the code I posted and it has a section that explains how C++ handles it "Under the Hood".
Thanks,
Raptor
-
*** Next question in understanding the code for "Manage different screens in a game". ***
Please refer to this link to see all of the code. https://github.com/SFML/SFML/wiki/TutorialScreens (https://github.com/SFML/SFML/wiki/TutorialScreens)
The "screen_0.hpp" and "screen_1.hpp" files contain both header and function definitions. There are no "screen_0.cpp" or "screen_1.cpp" files. Especially note that "screen_1.hpp" is supposed to hold the actual game itself. How can all of the code be in the header files?
Do the function definitions "have to reside" in the header files with no .cpp files in order for this concept to work?
Confused,
Raptor
-
*** Error msg when code entered into VC++ Express 2010 ***
I entered all of the code for "Manage different screens in a game" in VC++ Express 2010 setup for SFML 2.0.
I converted the code in all of the files from SFML 1.6 to 2.0. I got rid of all of the red error markers in all of the files except for one.
The one red error marker left is under the period in line-23 in the code below.
The error message is:
Error: No instance of overloaded function "std::vector<_Ty, _Ax>::push_back[with _Ty=cScreen*, _Ax=std::allocator<cScreen*>]" matches the argument list
There's no red marker in line 25.
Why is there a red error marker under the period in line-23 but not in line-25?
Here's the code for Main.cpp:
01 //
02
03 #include "stdafx.h"
04 #include <fstream>
05 #include <iostream>
06 #include <sfml/Graphics.hpp>
07 #include "screens.hpp"
08
09 int _tmain(int argc, _TCHAR* argv[])
10 {
11 //Applications variables
12 std::vector<cScreen*> Screens;
13 int screen = 0;
14
15 //Window creation
16 sf::RenderWindow App(sf::VideoMode(640, 480, 32), "SFML Demo 3");
17
18 //Mouse cursor no more visible
19 App.setMouseCursorVisible(false);
20
21 //Screens preparations
22 screen_0 s0;
23 Screens.push_back (&s0); //<<< Red error marker under the period in this line.
24 screen_1 s1;
25 Screens.push_back (&s1); //<<< No red error marker in this line.
26
27 //Main loop
28 while (screen >= 0)
29 {
30 screen = Screens[screen]->Run(App);
31 }
32
33 return EXIT_SUCCESS;
34
35 }
-
Why is there a red error marker under the period in line-23 but not in line-25?
Please keep in mind that Intellisense (the module that makes those red markings) isn't always a reliable source for error checking, sometimes things can also get marked although they compile fine, just because Intellisense hasn't cached everything right. So don't always trust the markings but look at the compiler/linker errors.
As for your problem, Intellisense only marks the first occuring problem with the same variable. And since you use twice the same vector it only marks the first one.
Although I'm not quite sure why it errors at the push_back, but I'd have to look again closer on what's allowed with polymorphism. ;)
The "screen_0.hpp" and "screen_1.hpp" files contain both header and function definitions. There are no "screen_0.cpp" or "screen_1.cpp" files. Especially note that "screen_1.hpp" is supposed to hold the actual game itself. How can all of the code be in the header files?
Do the function definitions "have to reside" in the header files with no .cpp files in order for this concept to work?
That's just bad/lazy programming from the creator of that (one year old) tutorial. You should always seperate the decleration (in .hpp file) and the definition (in .cpp file). ;)
-
That's just bad/lazy programming from the creator of that (one year old) tutorial. You should always seperate the decleration (in .hpp file) and the definition (in .cpp file). ;)
Unless you don't have definitions. :D (Only a sith deals in absolutes)
Show us the code you ported to sf 2.0, only thing that comes to mind is that your two screens aren't derieved from that base screen somehow but that'd quite unlikely.
-
Unless you don't have definitions. :D (Only a sith deals in absolutes)
Hu? If you don't have any definitions you don't create a .cpp file obviously (there's nothing to split then)... ;)
Also base classes often don't use cpp files although they have some definitions too, but one then uses inline definition. THis is then again subtile and can vary widely from person to person.
-
Hi FRex and eXpl0it3r,
I got the "Manage different screens in a game" ported to SFML 2.0 and working.
The reason for the red error flag under the period in "Screens.push_back (&s0);" in Main.cpp, was that there were errors in the screen_0.hpp and screen_1.hpp files.
I had not tried to compile the project and was only concentrating on trying to get rid of all red error flags in all files before compiling. Once I clicked the Debug arrow in VC++, I got the compile errors. After I corrected all of the compile errors in the screen_0.hpp and screen_1.hpp files, then the red error flag in the Main.cpp file went away.
Learned a lesson that red error flags in one file can actually be caused by errors in a different file.
Understand how the code in "Manage different screens in a game" works now, thanks to both of your help.
Thanks!
Raptor
-
Opps, forgot to ask another question. What's the "_INCLUDED" suffix on the pre-processor directives for? I've looked in all of my C++ books and did a bit of Googling but have not found an explanation for why it's needed.
#ifndef SCREENS_HPP_INCLUDED
#define SCREENS_HPP_INCLUDED
//Basic Screen Class
#include "screen.hpp"
//Including each screen of application
#include "screen_0.hpp"
#include "screen_1.hpp"
#endif // SCREENS_HPP_INCLUDED
-
Opps, forgot to ask another question. What's the "_INCLUDED" suffix on the pre-processor directives for? I've looked in all of my C++ books and did a bit of Googling but have not found an explanation for why it's needed.
The whole thing is called include guards and they are needed to prevent multiple inclusion/decelrations. If you now add _INCLUDED are not doesn't matter, in fact it should just be a unique name that nothing else in your code does ever #define. For more information just google 'include guards'. ;)
-
It's not needed but macros(something that was in C so you know it means trouble..) don't respect namespaces so they have to be something extremely ugly/stand out a lot so that you're unlikely to use it in normal code. So include guard usually contain name of file because it's unique but can have even more to be safer. sfml include guards are SFML_filename_HPP
'#define' is 'macro'
the '#ifndef' '#endif' blocks are used to do something called 'conditional compilation'
macros and #ifndef #endif blocks used like that are called 'include guards'
In vc++ you can use #pragma once (it works a bit differently and supposedly faster during compilation than include guards but in the end the effect is same) at the beggining of a header but it's not guaranteed to be on every compiler.
-
Hi eXpl0it3r and FRex,
Thanks for your responses. Prior to posting, I had done intensive Googling on "Include guards", "Preprocessor Directives", and "_INCLUDED". I found some sample code using it but no real explanations of why "_INCLUDED" is needed. I did notice that the "_INCLUDED" Google finds were related to C code rather than C++ code.
Would it be safe to say that in C++ there's no need to use the "_INCLUDED" suffix when using #ifndef and #define include guards?
If there's a reason why the "_INCLUDED" suffix is needed in C++ code, could you please explain why it's needed over never using it at all.
Thanks,
Raptor
-
It's NOT needed. It's not at all significant, macros are not code, it's preprocessor - it works in text, not code, the _INCLUDED can make it more intuitive, it could be whatever but should be in ALL CAPS, long and unique(for safety).
http://www.stroustrup.com/bs_faq2.html#macro - read this to understand why macros are evil and should have extremely unique names.
Conventions such as having macros (and only macros) in ALLCAPS helps, but there is no language-level protection against macros. (...) Macros operate on a program as a stream of characters before the compiler proper sees it
-
http://www.stroustrup.com/bs_faq2.html#macro - read this to understand why macros are evil and should have extremely unique names.
@FRex: Please keep in mind that include guards do not have anything to do with macros. The only thing they have incommon is that they both make use of the preprocessor. It completly okay and even adviced to use include guards with
#ifndef CLASS_HPP
#define CLASS_HPP
// Class decleration
#endif // CALSS_HPP
-
CLASS_HPP seems like an extremely unique name written in all caps.
-
CLASS_HPP seems like an extremely unique name written in all caps.
Ehrm, why so sarcastic? :o
I mean it's obvious that you'll have to replace that with your own class name... ::)
-
It wasn't sarcastic, <own class name>_HPP is extremely unique and in all caps like all macros should be.
-
It wasn't sarcastic, <own class name>_HPP is extremely unique and in all caps like all macros should be.
Oh well then it was kind of hard to figure that out, because it could've been read in both ways. ;D
Yes <own class name>_HPP is good and if you want you can also add _INCLUDED or _RAPTOR88_IS_AWESOME, it really doesn't matter code wise. ;)
-
It's NOT needed. It's not at all significant, macros are not code, it's preprocessor - it works in text, not code, the _INCLUDED can make it more intuitive, it could be whatever but should be in ALL CAPS, long and unique(for safety).
http://www.stroustrup.com/bs_faq2.html#macro - read this to understand why macros are evil and should have extremely unique names.
Conventions such as having macros (and only macros) in ALLCAPS helps, but there is no language-level protection against macros. (...) Macros operate on a program as a stream of characters before the compiler proper sees it
Since it's not needed, I won't use it. Interesting link you provided. All sorts of good info in it.
Thanks!
Raptor
-
Interesting link you provided. All sorts of good info in it.
Yes Bjarne Stroustrup's (FYI, he's the 'inventor' of C++) FAQs are quite a good read. ;)
If you're looking for good C++ books, you can take a look at Stroustrup's 'The C++ Programming Language', which is to some point a bit like a detailed reference manual, thus it's quite an intensive read.