I'm in the process of trying to make a game-in-progress more modular. I'd like to be able to declare a single array of all the room_t objects in the game (room_t rooms[]), store it in world.cpp and call it from other files.
The truncated code below does not work, but it's as far as I've gotten. I think I need to use extern but have not been able to find a method that works correctly. If I try and declare the array in the header file, I get a duplicate object error (as each file calls world.h, I'd assume).
main.cpp
#include <iostream>
#include "world.h"
int main()
{
int currentLocation = 0;
cout << "Room: " << rooms[currentLocation].name << "\n";
// error: 'rooms' was not declared in this scope
cout << rooms[currentLocation].desc << "\n";
return 0;
}
world.h
#ifndef WORLD_H
#define WORLD_H
#include <string>
const int ROOM_EXIT_LIST = 10;
const int ROOM_INVENTORY_SIZE = 10;
struct room_t
{
std::string name;
std::string desc;
int exits[ROOM_EXIT_LIST];
int inventory[ROOM_INVENTORY_SIZE];
};
#endif
world.cpp
#include "world.h"
room_t rooms[] = {
{"Bedroom", "There is a bed in here.", {-1,1,2,-1} },
{"Kitchen", "Knives! Knives everywhere!", {0,-1,3,-1} },
{"Hallway North", "A long corridor.",{-1,-1,-1,0} },
{"Hallway South", "A long corridor.",{-1,-1,-1,1} }
};
Just add extern room_t rooms[]; in your world.h file.
world.h
extern room_t rooms[];
The problem is that you're trying to reference a variable you've declared in the .cpp file. There's no handle on this outside of the scope of this file. In order to fix this, why not declare the variable in the .h file but have an Init function:
room_t rooms[];
void Init();
Then in the .cpp
void Init() {
// create a room_t and copy it over
}
Related
How can I define an integer in a header file so that each cpp file which includes the header will have static const int id=0 while giving the ability to cpps to redefine it with other value.
I tried to used weak symbol but couldn't make it work.
If you are ok with preprocessor definitions you could do this:
// header.h
#ifndef CLASSID
#define CLASSID 0
#endif
static int id=CLASSID;
// class.cpp
#define CLASSID 1
#include "header.h"
This way a source file may override the default, but may also omit it, which is the sort of weak approach you mentioned.
Here's another solution that uses static variables:
// log.h
#ifndef LOG_H
#define LOG_H
#include <iostream>
#define SETLOGID(v) static logidsetter _logidsetter(_logid, v);
#define LOG(v) std::cout << "id: " << _logid << ": " << (v) << std::endl;
class logidsetter
{
public:
logidsetter(int &id, int val)
{
id = val;
}
};
static int _logid = 0;
#endif
// myclass.h
class myclass
{
public:
myclass();
void run(void);
};
// myclass.cpp
#include "log.h"
#include "myclass.h"
SETLOGID(42)
myclass::myclass()
{
LOG("myclass::cons");
}
void myclass::run(void)
{
LOG("myclass::run");
}
// main.cpp
#include "myclass.h"
#include "log.h"
SETLOGID(1)
int main()
{
myclass mc;
LOG("here's main");
mc.run();
}
The log header defines the static int _logid and provides the macro SETLOGID and the class idsetter. The cpp file may use SETLOGID to redefine the static value. This is done with an instantiation of the class idsetter along with the address of _logid and the desired value. The trick allows to bypass C++'s One Definition Rule.
The output looks like:
id: 42: myclass::cons
id: 1: here's main
id: 42: myclass::run
I wrote down an example code to try to replicate the error I am getting in a school project about the scope of an object:
In file: classTest.cpp
#include "headerone.h"
#include "headertwo.h"
#include <iostream>
using namespace std;
int main() {
ClassOne* pntrObj1 = new ClassOne;
ClassTwo* pntrObj2 = new ClassTwo;
pntrObj1->testClassOne();
return 0;
}
In file: headerone.h
#ifndef HEADERONE_H
#define HEADERONE_H
#include "headertwo.h"
#include <iostream>
using namespace std;
class ClassOne {
public:
void testClassOne() {
cout << "One Worked\n";
pntrObj2->testClassTwo();
}
};
#endif
In file: headertwo.h
#ifndef HEADERTWO_H
#define HEADERTWO_H
#include <iostream>
using namespace std;
class ClassTwo {
public:
void testClassTwo() {
cout << "Two Worked";
}
};
#endif
To be clear, the error is: pntrObj2 was not declared in this scope. The error comes from the file headerone.h
If I had to guess, I need to somehow pass the reference but I am not sure where to start for that. Any help is appreciated.
The variable pntrObj2 is only visible inside the scope in which it was declared, in this case your function main(). In other words, only code inside the curly braces of main() would be able to use the name pntrObj2 to reference that variable. However you can pass that value to other pieces of code by making it the argument of a function call.
So maybe what you want to do is add an argument to the testClassOne() method, so you can pass in the value of pntrObj2. So pntrObj1->testClassOne(); would become pntrObj1->testClassOne(pntrObj2);, and where you define testClassOne you can add a corresponding parameter. I'll let you figure this out so as to not completely do your homework for you :)
Here you include your file a lot of time and in testClassOne function, you do not declare pntrObj2
use
void testClassOne() {
cout << "One Worked\n";
ClassTwo* pntrObj2 = new ClassTwo()
pntrObj2->testClassTwo();
}
insteed of
void testClassOne() {
cout << "One Worked\n";
pntrObj2->testClassTwo();
}
I think there are many solutions outside for my problem but I dont get it, I'm kind of new to structs - so please help me..
OK my problem is I declare a struct in my header.h file and there is a function also inside that puts a string in one of the struct values and in the header file I can also output the string, but I want that struct and that !!value!! in a different cpp file where I can access to that value - so here is my code
header.h
#include <iostream>
#include <string.h>
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
struct FUNCTIONS
{
std::string f_name;
};
//extern FUNCTIONS globalStruct;
//put in struct variable
void put2struct()
{
struct FUNCTIONS struct1;
struct1.f_name = "FUNCTION";
std::cout << "Functionname: " << struct1.f_name << std::endl;
}
#endif //FUNCTIONS_H
and main.cpp
#include <iostream>
#include <string.h>
#include "header.h"
using namespace std;
int main(int argc, char const *argv[])
{
struct FUNCTIONS globalStruct;
put2struct();
//FUNCTIONS struct1;
std::cout << "Functionname2: " << globalStruct.f_name << std::endl;
return 0;
}
I hope somebody can help me I really dont get it how to do this :/
There is no way to directly access a local variable outside the block where it is defined. Because struct1 is an automatic variable, it is destroyed when put2struct returns, and no longer exists after that.
You can write a function that takes a FUNCTIONS by reference, and modify put2struct to call that function. That way you can access struct1 from a different cpp file:
void foo(FUNCTIONS&);
void put2struct()
{
FUNCTIONS struct1;
// do your thing
foo(struct1);
}
// another file
void foo(FUNCTIONS& object) {
// you have access to the object passed by reference
}
Recently I've been learning how to create methods within classes so that I only have to write a method once and for each of that class I instantiate I can call the one method and it will work only on the variables of the object that called it, I know how to do this when only using main.cpp and no headers however I am confused on how I should be writing this when I use a class header and cpp.
I have a sample of code similar to what I want to achieve:
#include <iostream>
using namespace::std;
class Object
{
public:
int stuff;
void manageStuff();
Object();
};
void Object::manageStuff()
{
stuff++;
}
Object::Object() : stuff(0) {}
Object object1, object2;
int main() {
for (int i = 0; i < 10; i++)
{
object1.manageStuff();
object2.manageStuff();
cout << object1.stuff << "\n";
cout << object2.stuff << "\n";
}
}
This works fine and allows me to have two instances of Object and a method that works independently for each instance, this is my current project:
main.cpp:
#include <iostream>
#include "Test.h"
using namespace std;
int main()
{
Test test;
for (int i = 0; i < 10; i++)
{
test.count(); // Here's my error "undefined reference to Test::count"
}
return 0;
}
Test.cpp
#include <iostream>
#include "Test.h"
using namespace std;
Test::Test()
{
//ctor
}
Test::~Test()
{
//dtor
}
Test.h
#include <iostream>
#ifndef TEST_H
#define TEST_H
class Test
{
public:
Test();
virtual ~Test();
void count();
int counter();
};
#endif // TEST_H
and finally TestFunctions.h
#include <iostream>
#include "Test.h"
#ifndef TESTFUNCTIONS_H_INCLUDED
#define TESTFUNCTIONS_H_INCLUDED
void Test::count()
{
Test::counter++;
std::cout << Test::counter;
}
#endif // TESTFUNCTIONS_H_INCLUDED
I'm sure that there will be something that's very obviously wrong to a more seasoned programmer and I'm about to look a bit thick but any help would be greatly appreciated
Thanks!
I would suggest getting rid of TestFunctions.h, and adding the implementation of Test::count() to Test.cpp. Currently, the TestFunctions.h header is not included anywhere, so you have no access to the definition from main.
You defined (i.e. implemented) Test::count() in a header file (TestFunctions.h), but you never included it anywhere so the code there is not compiled.
You should change it to be in a .cpp file, compile it and link it with the other source files. There's no reason why not to place it in Test.cpp.
Rename TestFunctions.h into TestFunctions.cpp, make it compiled same way as main.cpp and linked.
Alternatively, include TestFunctions.h somewhere, e.g. main.cpp
In my Function.h file:
class Function{
public:
Function();
int help();
};
In my Function.cpp file:
#include "Function.h"
int Function::help() //Error here
{
using namespace std;
cout << "Help";
return 1;
}
In my Main.cpp
#include <iostream>
#include "Function.h"
using namespace std;
int menu(){
Function fc;
fc.help();
return 1;
}
int main(int args, char**argv){
return menu();
}
Error is : ‘Function’ has not been declared
Can anybody tell me why? Thank you.
I tried like this and the problem is solved, but I dont really understand why:
In Function.h file:
I use
class Function{
public:
int status;
Function():status(1){}
int help();
};
instead of the old one
class Function{
public:
Function();
int help();
};
All your include statements are missing the #:
#include "Function.h"
^
Everything else looks fine, though you need to also #include <iostream> in Function.cpp since you're using cout.
Here is the Function.cpp that I got to compile and run:
#include "Function.h"
#include <iostream>
int Function::help() // No error here
{
using namespace std;
cout << "Help";
return 1;
}
Function::Function()
{
}
I had a similar problem. Make sure that you only have the required header files. I had two header files both including each other and it spit out this mistake.
You have created a declaration for the constructor of the Function class without including it in your implementation (cpp file).
#include "Function.h"
Function::Function(){
// construction stuff here
}
int Function::help() //Error here
{
using namespace std;
cout << "Help";
return 1;
}
In the first Function.h file you have declared the constructor but not defined it. In the second Function.h file (the one that works) you have defined and declared the Function constructor. You can either define and declare in the header or file, or declare in the header file and define in the Function.cpp file.
For example, declare in the header file "Function.h":
class Function
{
Function();
}
and define here in "Function.cpp":
Function::Function(){}
Or the alternative is to declare and define in the header file "Function.h":
Class Function
{
Function(){}
}
The other thing that you have done in the second version of the header file is to initialise the member variable "status" in the "member initialisation list" which is a good thing to do (See Effective C++ by Scott Meyers, Item 4). Hope this helps :)