I'm working on making a game in C++. I have declared a Constant namespace used for global values that I need access to throughout the program. In there I have an ofstream for debugging purposes (yeah, I know it's not "constant" but it fits best there), which outputs only when it feels like it. I was able to make a small program demonstrating the problem. I apologize for it being spread across 4 files, but it is important, I promise.
main.cpp:
// Include necessary files
#include "test.h"
#include "constants.h"
#include <fstream>
using namespace std;
int main(int argc, char* argv[])
{
// Start of program
Constant::outstream.open("test.txt");
// ...
// Do stuff
// Output debugging info
Test test;
test.print("Test", Constant::outstream);
// ...
// Do other stuff
// End of program
Constant::outstream.close();
return 0;
}
constants.h:
#ifndef _CONSTANTS_H
#define _CONSTANTS_H
#include <fstream>
namespace Constant
{
static ofstream outstream;
}
#endif
test.h:
#ifndef _TEST_H
#define _TEST_H
#include <string>
#include <fstream>
#include "constants.h"
class Test
{
public:
void print(string str, ofstream& out);
};
#endif
test.cpp:
#include "test.h"
using namespace std;
void Test::print(string str, ofstream& out)
{
out << "out: " << str << endl << flush; // Works
Constant::outstream << "Constant::outstream: " << str << endl << flush; // Doesn't
}
In the test.cpp file, the out << ... line works as it should, while the Constant::outsream << ... line doesn't do anything even though I'm passing Constant::outstream as the out parameter! I don't see any reason why these two lines should be in any way different.
Before posting this, I tried putting test.cpp's code in test.h, just to have less files for the question, and was amazed to see it work. If I copy-paste the Test::print() function into test.h (whether inside or out of the class Test { ... }), then both output commands work correctly. the problem only occurs if Test::print()'s implementation is in a separate file.
It seems like any references to Constant::outstream simply don't work in class cpp files (no compile error, just nothing happens). It works in main.cpp and in class header files, but any class cpp file it seems not to. Unfortunately, this is a big program I'm writing so pretty much every class has its own cpp implementation file, and that's really the one place I need to use this ofstream. Does anyone know the reason for this?
Thanks in advance,
Doug
Constant::outstream has internal linkage, thus a separate instance is created for each translation unit. In short, Constant::outstream in test.cpp and main.cpp are two different variables.
§3.5.2 A name having namespace scope (3.3.6) has internal linkage if it is the name of
— a variable, function or function template that is explicitly declared static; or,
On the other hand, static class members would be visible throughout the program.
So, if you would write
struct Constant
{
static ofstream outstream;
}
instead of
namespace Constant
{
static ofstream outstream;
}
it would work.
However, note that the class must have external linkage; e.g. you should not put in in anonymous namespace.
Related
So I was trying to access a method that is defined in another class and has the prototype in the header. I'm pretty positive I defined it but it keeps popping up undefined reference to SafeCracker.
Main.cpp
#include <iostream>
#include "mystuff.h"
using namespace std;
void BigDog(int KibblesCount);
int main()
{
cout << SafeCracker(1);
return 0;
}
mystuff.cpp
#include <iostream>
using namespace std;
string SafeCracker(int SafeID)
{
return "123456";
}
mystuff.h
using namespace std;
#ifndef MYSTUFF_H_INCLUDED
#define MYSTUFF_H_INCLUDED
string SafeCracker(int SafeID);
#endif // MYSTUFF_H_INCLUDED
Here it tells you that you have an undefined reference, so you don't really have a problem with the prototype.
Had you forgotten to include the header file that contains the prototype you would have gotten something like
main.cpp: In function ‘int main()’:
main.cpp:8:13: error: ‘SafeCracker’ was not declared in this scope
cout << SafeCracker(1);
Your undefined reference is a linker error. The most likely cause would be that you did not use mystuff.cpp when compiling
If you're compiling from the command line, you should give both files as parameters.
If you're using an IDE that calls the compiler, make sure that the file is part of the project.
For example in Code::Blocks right-click on the file name and go "add to project" (If I remember correctly)
It is also possible that you made a typo in the function declaration in mystuff.cpp (that doesn't seem to be the case here though)
Now there is one important thing about your code you should take note of:
It is very bad practice to put a using namespace in a header file.
using namespace std; in a .cpp source file is mostly up to you, and that using statement will only apply to that particular file.
But if you put it in a header file that is meant to be included through #include , the using there will be forced upon any code that includes it.
Here is an example:
main.cpp
#include <iostream>
// including mystuff.h to use that awesome SafeCracker()
#include "mystuff.h"
// I need to use an std::map (basically an associative array)
#include <map>
// the map of my game
class map
{
int tiles[10][10];
};
int main()
{
// The std map I need to use
std::map<int, int> mymappedcontainer;
// The map of my game I need to use
map mytiles;
// The reason why I need to include mystuff.h
cout << SafeCracker(1);
return 0;
}
Normally, my class map should not be a problem since the map I included from the standard library is inside the namespace std, so to use it you would need to go std::map.
The problem here is that, since mystuff.h has using namespace std; in it, the symbol map is already used, and that creates a conflict.
You do not now who will use your header files, or if you will use them again a long time from now, and maybe then you will want to use name that is already used in the std namespace.
I advise you to use std:: before things taken from the standard libraries instead (std::string instead of just string for example)
PS: In C++, "class" refers to a class data structure, and the functions you made here are not part of any class. You should say "defined in another file" or "defined in another translation unit" instead
All I'm trying to do is create a separate class to hold my Hello World function (this is for a class), but I am getting an "identifier is undefined" compiler error. What is the issue?
Here is my main function (helloworld.cpp):
#include <iostream>
using namespace std;
int main() {
print_me();
system("pause");
return 0;
}
And here is the header class (helloworld.h) :
#include <iostream>
void print_me() {
std::cout << "Hello World\n";
}
You have not included helloworld.h in helloworld.cpp. The following code should work:
#include <iostream>
#include "helloworld.h"
using namespace std;
int main() {
print_me();
system("pause");
return 0;
}
One thing to remember is from your compiler's point of view, there is no connection between the two files unless you specify it. The fact that both files have the same name does not have any significance for compiler.
Side note 1: Consider using include guards in your header files. For simple projects, it may not be obviously necessary but for larger projects, not using them can lead to annoying ambiguous compilation errors.
Side note 2: Implementing function bodies in header files is generally discouraged.
Goal: Using the class variable so that an ifstream declared in an object's member can be used by the following member of the same object, without having to use function header parameter passing.
Problem: The local ifstream of the created object test isn't being re-used in the second member of that object. I must be setting it up wrong, how do I fix this?
Classes and files feel like climbing a mountain to me right now, but I can't even find the first foothold - getting the blasted variable to work! I looked around the net for too long but all examples are convoluted, I just want to have something basic working to start tinkering with. I'm dead sure it's something stupidly easy that I'm missing, really frustrating >:[
main.cpp
#include "file.h
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
file test;
test.file_pass();
return 0;
}
file.h
#ifndef FILE_H
#define FILE_H
#include <fstream>
#include <iostream>
using namespace std;
class file
{
public:
file();
void file_pass();
//private:
ifstream stream;
};
#endif
file.cpp
#include "file.h"
//**********************************
//This will read the file.
file::file()
{
ifstream stream("Word Test.txt");
}
//**********************************
//This will output the file.
void file::file_pass()
{
//ifstream stream("Word Test.txt"); //if line activated, program works fine of course.
string line;
while(getline(stream, line))
cout << line << endl;
}
Here you are creating a new local variable with the same name as the class member:
file::file()
{
ifstream stream("Word Test.txt");
}
Instead you can use this to initialize the class member in the constructor:
file::file() : stream("Word Test.txt")
{
}
I am writing a class and need to separate the declarations from the implementation, but I keep receiving "undefined reference" errors when compiling and linking my test program. It works fine when I include the implementation in the .h file, so I believe I am doing something wrong in there. I just can't figure out what.
Huge_Integer.h
#ifndef HUGE_INTEGER_H
#define HUGE_INTEGER_H
#include <vector>
#include <string>
using namespace std;
class Huge_Integer
{
public:
Huge_Integer();
Huge_Integer(string);
void input();
string output();
void add(Huge_Integer);
void subtract(Huge_Integer);
bool is_equal_to(Huge_Integer);
bool is_not_equal_to(Huge_Integer);
bool is_greater_than(Huge_Integer);
bool is_less_than(Huge_Integer);
bool is_greater_than_or_equal_to(Huge_Integer);
bool is_less_than_or_equal_to(Huge_Integer);
private:
vector<int> value;
};
#endif
Huge_Integer.cpp
#include<vector>
#include<string>
#include<iostream>
#include "Huge_Integer.h"
using namespace std;
// all stubs for now...
Huge_Integer::Huge_Integer()
{
cout << "object created\n";
}
Huge_Integer::Huge_Integer(string s)
{
cout << "object created\n";
}
//etc...
It also works if I put #include "Huge_Integer.cpp" in my test file, but I shouldn't have to do that, right?
I am using MinGW.
Thanks in advance!
Edit: Added stubs from my .cpp file
Sounds like a linking issue.
What that means is that you have to compile your class first -- this will create a compiled object file.
Then compile the main program while passing in this compiled version of the class.
Like this:
g++ -c huge_integer.cpp
g++ main.cpp huge_integer.o
Substitute your mingw command for g++ if it is different.
Not related to linking, but you are referring to Huge_Integer inside the class declaration itself.
At least with g++, you should add a forward declaration before so that Huge_Integer has meaning inside the class declaration thus:
class Huge_Integer; // forward declaration
class Huge_Integer {
Huge_Integer();
// etc...
void add(Huge_Integer);
Note: I don´t have comment privileges, so I had to type in the answer box.
I am having problems with a class I am writing. I have split the class into a .h file that defines the class and an .cpp file that implements the class.
I receive this error in Visual Studio 2010 Express:
error C2039: 'string' : is not a member of 'std'
This is the header FMAT.h
class string;
class FMAT {
public:
FMAT();
~FMAT();
int session();
private:
int manualSession();
int autoSession();
int mode;
std::string instructionFile;
};
This is the implementation file FMAT.cpp
#include <iostream>
#include <string>
#include "FMAT.h"
FMAT::FMAT(){
std::cout << "manually (1) or instruction file (2)\n\n";
std::cin >> mode;
if(mode == 2){
std::cout << "Enter full path name of instruction file\n\n";
std::cin >> instructionFile;
}
}
int FMAT::session(){
if(mode==1){
manualSession();
}else if(mode == 2){
autoSession();
}
return 1;
}
int FMAT::manualSession(){
//more code
return 0;
}
this is the main file that uses this class
#include "FMAT.h"
int main(void)
{
FMAT fmat; //create instance of FMAT class
fmat.session(); //this will branch to auto session or manual session
}
My inability to fix this error is probably a result of me not understanding how to properly structure a class into separate files. Feel free to provide some tips on how to handle multiple files in a c++ program.
You need to have
#include <string>
in the header file too.The forward declaration on it's own doesn't do enough.
Also strongly consider header guards for your header files to avoid possible future problems as your project grows. So at the top do something like:
#ifndef THE_FILE_NAME_H
#define THE_FILE_NAME_H
/* header goes in here */
#endif
This will prevent the header file from being #included multiple times, if you don't have such a guard then you can have issues with multiple declarations.
Your FMAT.h requires a definition of std::string in order to complete the definition of class FMAT. In FMAT.cpp, you've done this by #include <string> before #include "FMAT.h". You haven't done that in your main file.
Your attempt to forward declare string was incorrect on two levels. First you need a fully qualified name, std::string. Second this works only for pointers and references, not for variables of the declared type; a forward declaration doesn't give the compiler enough information about what to embed in the class you're defining.
Take care not to include
#include <string.h>
but only
#include <string>
It took me 1 hour to find this in my code.
Hope this can help