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")
{
}
Related
This is the header file File.h:
#include "common.h"
#ifndef FILE_H
#define FILE_H
using namespace std;
class File : public fstream{
public:
string file;
File(){
File("/tmp/text");
}
File(string file_name): file(file_name), fstream(file_name.c_str(), fstream::in | fstream::out){
}
void read_line();
};
#endif
And this is the File.cpp file:
#include "File.h"
void File::read_line(){
string line;
while(getline(*this, line)){
cout << "line: " << line << endl;
}
}
And following is the content of common.h
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <string.h>
#include <string>
#include <stdio.h>
#include <stack>
#include <unistd.h>
#include <cassert>
#include <stdexcept>
#include <getopt.h>
#include <fstream>
#include <istream>
When compiling above code, I get below error:
/home/rohit/cpp/cmake_projs/tree/src/File.cpp: In member function ‘void File::read_line()’:
/home/rohit/cpp/cmake_projs/tree/src/File.cpp:7:24: error: no matching function for call to ‘File::getline(File&, std::__cxx11::string&)’
while(getline(*f, line)){
^
In file included from /usr/include/c++/7/iostream:40:0,
from /home/rohit/cpp/cmake_projs/tree/include/common.h:1,
from /home/rohit/cpp/cmake_projs/tree/include/File.h:1,
from /home/rohit/cpp/cmake_projs/tree/src/File.cpp:1:
But the code compiles fine when I put almost same code in a different function not related to File class:
void test(){
string line;
File *f = new File("/tmp/abc");
while(getline(*f, line)){
cout << "line: " << line << endl;
}
}
Why is this standard function hidden in the class function read_line() and not in an independent function?
It is a case of name lookup not working the way you expected.
Your class File inherits from fstream which inherits from istream. And istream has a member function getline, or two actually.
When you call an unqualified getline inside the class member, the compiler finds the inherited getline member and then doesn't look any further. In the free function test() there is no member function, so the compiler instead looks for the functions brought in by using namespace std;.
A solution is to explicitly use std::getline(*this, line) to show that you want to call a free function and not a member function.
This might also be yet another reason for not doing using namespace std;, but instead use std:: to refer to standard library names.
It is because fstream has a member getline that does not match, change the call to std::getline and it will work.
Here is my file.h :
#define MAXCOMPONENTS 20
#include <string>
#include <string.h>
#include <iostream>
class file{
public:
file(char const * filename);
virtual ~file();
void Takeinfocomponents();
void Takeshape();
void Getvalue(int i);
char *Getcomponents();
char *Getcolor();
protected:
private:
char const * filename;
String shape;
int value[MAXCOMPONENTS];
char components[MAXCOMPONENTS];
char color[MAXCOMPONENTS];
};
And my file.cpp :
#include <fstream>
#include <iostream>
#include <string.h>
#include <string>
#include "file.h"
using namespace std;
file::file(char const* filename)
{
cout << "constructor/fichier:" << filename << endl;
ifstream fichier(filename,ios::in);
if(fichier){
this->filename=filename;
fichier.close();
Takeshape();
Takeinfocomponents();
}else{
cout << "File name invalid." << endl;
}
}
file::~file()
{
}
char* file::Getcolor(){
return this->color;
}
char* file::Getcomponents(){
return this->components;
}
void file::Getvalue(int i){
cout << this->value[i] << endl;
}
void file::Takeinfocomponents(){ // pic up name of components, his number and his color
cout << "Takeinfocomponents/fichier:" << filename << endl;
ifstream fichier(this->filename,ios::in);
ifstream stop(this->filename,ios::in);
string line;
int i=0;
getline(fichier,line);
getline(stop,line);
getline(stop,line);
while(line!="/" && i!=99){ // take all informations while the stop signal isn't read
getline(stop,line);
fichier >> this->components[i] >> this->value[i] >> this->color[i];
cout << this->components[i] << this->value[i] << this->color[i] << endl;
i++;
}
fichier.close();
}
void file::Takeshape(){ // pic up the shape in .txt
cout << "Takeshape" << endl;
fstream fichier(this->filename,ios::in);
string shape;
fichier >> shape;
this->shape=shape;
fichier.close();
}
This is a part of a larger programm who make graphic from informations ( from the .txt ), this part is use to pic up informations from the .txt.
The problem come from the declaration of the :
String shape;
He told me that string is not a name type. I've tried with a small "s" :
string shape;
But this ain't working.
I've the impression that i miss a very small things that could unlock my problem.
Thx for help.
Notabene : I'm french and my english is not this good, please answer like i was a little child ahah !
You have to explicitly state the namespace:
std::string shape;
You shouldn't pollute the namespace in the headers, so using namespace std is not an option here.
See also the question about namespace pollution. If you just need strings, prefer to use
using std::string;
in the cpp file.
C++ uses the concept of a namespace. A namespace is used to group types, variables, etc. together in a meaningful way, regardless of the number of header files those types or variables are spread across.
In this example, the string type is inside the std namespace. std is short for Standard Template Library, and it is the namespace that most of C++'s library classes, etc. are stored in.
The correct way of accessing type inside a namespace is namespace::type, so the correct way of accessing the string type inside the std namespace is std::string. You can also write using namespace std to access the types in std without having to write std:: each time, but doing this in a global scope is a bad idea, because it pollutes the global namespace.
In the code you posted, string shape; appears before using namespace std, as the #include "file.h" appears before it. Therefore, it won't take effect.
To be able to use the string class and create string objects, you need to include...
#include <string>
... at the top of your header files.
You do not need...
#include <string.h>
The string class, like all STL classes, is part of the std namespace. If you do not want to write std:: before every class name, you can simply state...
using namespace std;
... at the top of your header files so that instead of...
std::string shape;
... you can simply use...
string shape;
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.
I am trying to link several object files and I am getting 3 undefined reference to a function errors.
inputtest.cpp
//test of input methods
#include <iostream>
#include <string>
#include <fstream>
#include <string>
#include <vector>
#include "Vector.h"
#include "Particle.h"
#include "read_particle_input.h"
#include "User_input.h"
#include "Particle_vector.h"
using namespace std;
using namespace berger_DEM;
int main() {
Particle_vector particles;
User_input input_data;
read_particle_input(particles, input_data);
cout <<endl<< particles.getpart(1).rho()<<endl<<particles.getpart(1).radius()<<endl;
return 0;
}
I am linking it with 5 object files with the names found in the ".h" files(just .o files compiled from .cpp files of the same name). One of the errors I receive is
undefined reference to 'berger_DEM::read_particle_input(berger_DEM::Particle_vector&, berger_DEM::User_input&)
note that this function has a prototype in read_particle_input.h and is implemented in read_particle_input.o. I am also getting two other undefined references, but I believe they are the same issue and if i can solve this one, the same solution should work for those two.
prototype:
namespace berger_DEM
{
void read_particle_input(Particle_vector&,User_input&);
}
implementation:
//method to read in particle_input.dat
void read_particle_input(Particle_vector & particles, User_input & input_data)
{
//define local variables
Vector velocity_in;
Vector position_in;
double radius_in;
double rho_in;
//open file and define file pointer
std::ifstream particle_input ("particle_input.dat");
//go through each line in particle_input.dat and define each particle
if (particle_input.is_open()) {
for(int i=0;i<input_data.num_particles();i++) {
//read one line from particle_input.dat
particle_input >> position_in;
particle_input >> radius_in;
particle_input >> rho_in;
particle_input >> velocity_in;
//set particle properties and position/velocity
particles.getpart(i).setrho(rho_in);
particles.getpart(i).setradius(radius_in);
particles.getpart(i).move(position_in);
particles.getpart(i).accelerate(velocity_in);
}
}
//close file
particle_input.close();
}
I've been looking all over for someone who had the same issue, but I was unable to find anything.
Thanks for the help.
Your implementation is missing the class scope.
change
void read_particle_input(Particle_vector & particles, User_input & input_data)
{
//define local variables
to
void berger_DEM::read_particle_input(Particle_vector & particles, User_input & input_data)
{
//define local variables
In implementation file it should be defined as,
void berger_DEM::read_particle_input(Particle_vector& particles, User_input& input_data);
{// ^^^^^^^^^^^ specify that 'read_particle_input' is part of the namespace
//...
}
I have the following class definition, written in C++, residing in it's own header file (ManageFeed.h)
#include <string>
#include <fstream>
#include <iostream>
#include <cstring>
class ManageFeed
{
bool get_feed();
void format_feed();
bool refresh_feed();
int find_start_of_string(string tag, ifstream& rssfile);
public:
void display_feed_list();
void display_feed_item();
ManageFeed();
};
When I try to compile this code, I get the following error
custom-headers/ManageFeed.h:22: error: ‘string’ has not been declared
custom-headers/ManageFeed.h:22: error: ‘ifstream’ has not been declared
I find that I can successfully compile the code without any errors if I remove the parameters from the int find_start_of_string() function, but aren't the parameters required if data is to be passed into the function? If I try to call this function from main(), I receive the following error
reader.cpp:6: error: prototype for ‘void ManageFeed::find_start_of_string(std::string, std::ifstream&)’ does not match any in class ‘ManageFeed’
so they are clearly required for the function to be usable. The textbook I'm using has examples of class definitions in their own head files with parameters present, but there seems to be no other difference in the structure of my code, nor is there any explanation given for why the books code works and mine doesn't.
Question: Are the parameters not required in the definition (the function definitions in ManageFeed.cpp have parameters specified) or am I doing something wrong here?
If anybody's interested, here's my application file
#include "custom-headers/ManageFeed.h"
using namespace std;
ifstream rssfile;
const string tag;
void ManageFeed::find_start_of_string(string tag, ifstream& rssfile);
int main()
{
ManageFeed manage_example;
rssfile.open("rss.xml");
manage_example.find_start_of_string(tag, rssfile);
return 0;
}
and the implementation file for ManageFeed
#include "ManageFeed.h"
#include <iostream>
#include <string>
#include <cstring>
ManageFeed::ManageFeed()
{
}
/*
A function that will get the location of the RSS file from the user
*/
bool ManageFeed::get_feed()
{
cout << "Please specify the location of the feed: " << endl << endl;
cin >> feed_source;
return true;
}
void ManageFeed::store_feed()
{
ifstream source_feed;
source_feed.open(feed_source);
ifstream local_feed;
local_feed.open
(
"/../File System/Feed Source Files/Example Feed/Example Feed.xml"
);
local_feed << source_feed;
}
int ManageFeed::find_start_of_string(string tag, ifstream& rssfile)
{
bool return_value = false;
string line;
size_t found;
do
{
getline(rssfile, line, '\n');
found = line.find(tag);
if (found != string::npos)
{
return_value = true;
return found;
}
} while (!return_value && !rssfile.eof());
if (!return_value)
{
}
}
John has the right solution. Here is the reasoning.
Both string and ifstream live in a namespace called std. When you say string you are telling the compiler to look into the global namespace and find a token called string. There is no such thing. You have to tell the compiler where to find string.
To do so you can either prefix them with std::string and std::ifstream or you can add using namesapce std; at the top of your header file.
Looking a little more closely, you do have the using directive in you .cpp file, but you put it after you include the header. That means the compiler parses the header without the namespace and then parses the rest of the file with it. If you just move the using directive above the header include, it will also fix your problem. Note, however, that anything else using the header will also need to do that same. Thus, start your .cpp file this way:
using namespace std;
#include "custom-headers/ManageFeed.h"
Change:
int find_start_of_string(string tag, ifstream& rssfile);
to:
int find_start_of_string(std::string tag, std::ifstream& rssfile);
Aside: why were there so many questions just like this one today?