sounds like a great party to me!
if you're interested, I know exactly why your program wouldn't compile when you divided everything up.
C and C++ programs are compiled into 'translation units', which are basically little tiny libraries that make up
a portion of a program. You can see this directly if you compile without linking, which will produce a number of
object files, which are functionally the same as a translation unit, as far as I am aware.
When you declare a global variable, the variable is global
only to that translation unit. To be able to
see that global variable from another translation unit, it has to be able to see it through a link.
When you build an exe, the linker resolves links between the TUs to detemine how they 'see' one another.
The reason that your globals weren't working was actually because #include pastes the entire contents of a file
wherever it's written. So, for instance:
//highlander.h
#pragma once
int highlander;
int give_supreme_power();
//highlander.cpp
#include "highlander.h"
int give_supreme_power() {
if (highlander == 0) {
highlander = 1;
return 1;
}
return 0;
}
//main.cpp
#include <cstdio>
#include "highlander.h"
int main() {
if (!highlander) {
printf("quickening highlander!\n");
if (give_supreme_power()) {
printf("OH YEAH\n");
if (highlander) {
printf("ROLL CREDITS\n");
} else {
printf("wait what\n");
}
} else {
printf("huh, guess we already did that\n");
}
}
}
using msvc, that doesn't compile. "int highlander" is multiply defined, because that code is completely identical
to this:
//highlander.cpp
int highlander;
int give_supreme_power();
int give_supreme_power() {
if (highlander == 0) {
highlander = 1;
return 1;
}
return 0;
}
//main.cpp
#include <cstdio>
int highlander;
int give_supreme_power();
int main() {
if (!highlander) {
printf("quickening highlander!\n");
if (give_supreme_power()) {
printf("OH YEAH\n");
if (highlander) {
printf("ROLL CREDITS\n");
} else {
printf("wait what\n");
}
} else {
printf("huh, guess we already did that\n");
}
}
}
since #include is just dumbly pasting in. Obviously this can't work, because there can only be one highlander.
the extern keyword lets the linker know that it should find a global variable with the same name. Just defining an extern variable isn't enough, just the same way that putting a phone number for a nonexistent pizza place into your local phone directory doesn't mean you can now order pizza, if you couldn't before. The thing that the extern is linking to actually has to exist in exactly one of your source files.
So, this version of the example works:
//highlander.h
#pragma once
extern int highlander;
int give_supreme_power();
//highlander.cpp
#include "highlander.h"
int highlander;
int give_supreme_power() {
if (highlander == 0) {
highlander = 1;
return 1;
}
return 0;
}
//main.cpp
#include <cstdio>
#include "highlander.h"
int main() {
if (!highlander) {
printf("quickening highlander!\n");
if (give_supreme_power()) {
printf("OH YEAH\n");
if (highlander) {
printf("ROLL CREDITS\n");
} else {
printf("wait what\n");
}
} else {
printf("huh, guess we already did that\n");
}
}
}
And that should be that! that last one will compile.
As a bonus, you can see the global initialization rules in action in this program. Since we expect highlander to start as zero, all we have to do is name it.
All in all this kind of looks more like a C program than a C++ program with all those structs instead of classes with all public members. Might want to look into that. Also you're still seemingly putting everything into the same file altho you're no longer putting everything in the main function. Might want to split stuff up a bit? Learn how to do classes properly with a header and a source file? You generally put the class definition in a .h or .hpp header file and the implementation in a .cpp source file and then just include the header from where you need the class.
Using 'structs' or 'objects' to name your data structures has nothing to do with their 'object orientedness', it has to do with how their data is accessed. Really, both are identical in memory, it's just that all fields of a struct are public by default, and all fields of an object are private by default. Unless it's super duper important that access to a field be hidden, having to write a bunch of getters and setters to basic values is lots of typing for absolutely no gain. If everything in all of your objects is public anyway, calling them structs does nothing but save keystrokes.
Hope that helped in some way! There's a lot of stuff I wish someone had told me about C++ when I was starting out, so I'm happy to share. I mean, assuming you want to read all this gnarly gibberish