Read file and store it in protected variable in c++ - c++

I'm trying to read a file and store it in a protected variable. All methods are in the same class.
class A: public B
{
public:
//method declarations
protected:
string d;
};
void A::l(std::string filename)
{
ifstream ifs;
ifs.open(filename);
string d { istreambuf_iterator<char> {ifs}, istreambuf_iterator<char> {} };
ifs.close();
}
void A::f(void)
{
std::cout << d.length() << std::endl;
}
When I try to print the length of the string, it is 0. When I try to print d in f(), nothing is printed. I need d to be a protected variable and I cannot change the methods either. How do I pass the read file string to f method?

You assigned to a local, use the member (this-> is optional here):
this->d.assign(istreambuf_iterator<char> {ifs}, {});
If that doesn't help, you're probably specifying the file name wrong.
Try an absolute path (e.g. /home/user/file.txt or C:\Documents\User\Documents\file.txt) or check the working directory of your program.
You can always check for errors:
if (!ifs) throw std::runtime_error("File could not be opened");

Your problem has nothing to do with the fact that your variable is protected. The problem is that you are defining another variable with the same name. To avoid this problem some people append an underscore to the name of the variables, like 'd_', and other people write 'm_d'. But you don't need to do that if you don't want to.
One way to do what you want to do is the following:
class A
{
public:
void l(std::string filename);
void f();
//method declarations
protected:
string d;
};
void A::l(std::string filename)
{
ifstream ifs{filename};
if(!ifs)
return; // error
std::copy(istreambuf_iterator<char>{ifs},
istreambuf_iterator<char>{},
std::back_inserter(d)); // this is A::d
}
You don't need to use 'this->'. In fact in C++ you never use 'this' (only in sentences like 'return *this').
Also, in C++ you don't write:
void f(void);
but instead, you write
void f();
And also you don't need to close the ifstream. The destructor is going to do it for you.

Related

Can I use a member variable of type ofstream initialized in the class constructor?

I'm having issues declaring a constructor of an inherited class.
class Report{
public:
string fileName;
std::ofstream outputFile;
Report(string fileName, ofstream outputFile) {
fileName = fileName;
outputFile = outputFile; //<-- error here
}
void returnFile(string, ofstream);
void Report::returnFile(string name, ofstream file){
file.open(name);
}
};
class financialReport: public Report{
public:
void electorateHappenings();
void electorialImpact();
double finances();
void writetoFile();
financialReport(string fileName, ofstream outputFile)
:Report(fileName, outputFile) { } //<-- error here
};
the error occurs on the 3rd last line :Report(fileName, outputFile).
This line produces the error:
function "std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const
std::basic_ofstream<_CharT, _Traits> &) [with _CharT=char,
_Traits=std::char_traits<char>]" (declared at line 848 of
"C:\MinGW\lib\gcc\mingw32\9.2.0\include\c++\fstream") cannot be referenced
-- it is a deleted function
Is it not possible to create a constructor including ofstream?
The error also occurs on line 9 with outputFile = outputFile.
Thank you.
You can't pass it by copy, you can't copy one, but you can pass it by reference and initialize it in the initializer list of the class:
Demo
class Report {
public:
string fileName;
std::ofstream &outputFile; //reference here
// reference parameter, and initializer list
Report(string fileName, ofstream &outputFile) : outputFile(outputFile) {
fileName = fileName;
}
//...
};
Do the same in financialReport:
financialReport(string fileName, ofstream& outputFile) : Report(fileName, outputFile) {}
^
Note that this is a solution to the problem posed in the question, as normal, but in a more deep analysis, though you don't go in detail about what you want to achieve, I wouldn't go so far as to say it's a wrong approach, but odds are you can structure your program in a better way.
Yes, you can, but the error is telling you that you cannot copy an object of std::ofstream.
Depending on what you want to do, there are two ways to handle it.
Pass the ownership of std::ofstream to your newly created object:
Report(string fileName, ofstream outputFile) :
fileName{std::move(outputFile)},
outputFile{std::move(outputFile)}
{
}
//creation of object:
std::ofstream ofs {"filename.txt"};
Report report {"filename.txt", std::move(ofs)};
//ofs is empty here, it's whole content has been transferred to report object
Pass a reference to existing std::ofstream object:
class Report{
public:
string fileName;
std::ofstream& outputFile;
Report(string fileName, ofstream& outputFile) :
fileName{std::move(outputFile)},
outputFile{outputFile}
{
}
//creation of object:
std::ofstream ofs {"filename.txt}";
Report report {"filename.txt", ofs};
//you can use ofs from both here and from inside of report, but
//you have to ensure that ofs lives as long as report will use it or else you will enter Undefined Behaviour land
Note: If you want to have the same names for class members and for constructor arguments, you need to use member initializer list, like I did. If you decide to use references, you are required to use it as well.

Problems while opening a .dat file in c++

so basically I was trying to save a class inside a .dat file but in my code but it says this error No matching member function for call to 'open' but I put fstream header. I don't know if I'm writing something wrong. I use Xcode 10.
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
memberinformation()
{ name="not assigned" ;
phonenumber=0;
memberid=0;
}
int option3();
int option2();
int option1();
int option4();
};
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app,ios::binary) //this is where I get the error.
f.write((char*)&k,sizeof(k));
}
You are lucky to have been stopped by a simple error. #Alex44 has already shown how to get rid of the error:
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
But the following line is even worse:
f.write((char*)&k,sizeof(k));
because the compiler will not show any error, while the content of the string will not be saved in the file. std::string is not trivially copiable and because of that, the memberinformation class is not either. So you should not try to write it to a file as raw bytes.
You should instead write a serialization function that writes to a binary stream (just a possible serialization way):
phonenumber as a long int (no problem there)
memberid as an int (no problem there)
name.size as a size_t
name.data as name.size bytes
The other two answers have answered:
Why its not compiling.
Why its a bad idea to write binary objects.
I would suggest that you serialize the object via the standard C++ technique of using the stream operators. This makes writting/reading the objects trivial and usually makes debugging problems easy.
Using the format suggested by #serge-ballesta in his post:
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
// OLD STUFF GOES HERE
void swap(memberinformation& other) noexcept
{
using std::swap;
swap(name, other.name);
swap(phonenumber, other.phonenumber);
swap(memberid, other.memberid);
}
friend std::ostream& operator<<(std::ostream& str, memberinformation const& data)
{
return str << data.phonenumber << " "
<< data.memberid << " "
<< data.name.size() << " "
<< data.name << " ";
}
friend std::istream& operator<<(std::istream& str, memberinformation& data)
{
memberinformation tmp;
std::size_t nameSize
if (str >> tmp.phonenumber >> tmp.memberid >> nameSize) {
// All sizes were read correctly.
tmp.name.resize(nameSize);
if (str.ignore(1).read(&tmp.name[0], nameSize)) {
// ignored the space and read the name correctly.
// So now we update the "data" object
tmp.swap(data);
}
}
return str;
}
};
Now in your code:
int main()
{
memberinformation object;
std::cout << object;
std::cin >> object;
std::ofstream file("Data.dat");
file << object;
}
You miss a semicolon and you need to "bitwise or" your flags:
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
...
}
The answers above address your initial problem. I'm going to talk about two more.
First, you probably should f.close() at the end of your method. It may be perfectly fine to let it drop out of scope and clean up from there, but I personally think that's ugly, and I wouldn't count on it.
Second, I wouldn't store the data in binary unless there's a really good reason to do it. It won't be portable. Serge above suggests a serialization method. I'd consider an alternate approach. I'd write to the file in a human readable form such as JSON. Yes, it's a little more work, but...
-If you change your class, your old files will still be readable
-They are portable across environments
-You can actually look at them and readily understand what they contain
So Serge's suggestions above aren't horrible, but I'd pick a more modern serialization / deserialization style.
Note that your f.write won't work because your object contains other objects, you don't know how they work under the hood. That string, for instance, almost certainly can't be dumped the way you're trying to do it. Plus you aren't only dumping your data.
Also, you should printf the sizeof(k). You might find it interesting information. Try to account for every byte. You could printf the sizeof(k.name) to help you work some of it out.
I'm almost positive the information doing so would surprise you, but I haven't actually done it myself, because I would never try to raw memory copy C++ objects, and that's in effect what you're trying to do.

Returning a map from a class C++

I've written a class that reads in a map. But I need the map to be editable outside of the class. So my question is how can I return a map.
class ReadMap
{
string fileName;
public:
//constructors and destructor
ReadMap(){fileName="blank.txt";}
ReadMap(string name){fileName=name;}
~ReadMap(){}
//Function to print out visible list
void show()
{
LineDatabase Entry;
int LineNumber=100;
string buffer;
ifstream myfile (fileName.c_str() );
while (myfile.good())
{
myfile >> LineNumber >> ws;
getline (myfile, buffer);
Entry.insert(pair<int, string>(LineNumber, buffer));
cout <<buffer << endl;
}
//return Entry;
}
};
You may be better off by having the caller of show() pass in a reference to the map to be filled, as returning a map tends to have high overhead. Something like this:
void show(LineDatabase& Entry) {
// do your map readin logic
return;
}
You return a map just like you return anything else—using the return keyword. If you're wondering why your commented out return doesn't work, it's because you declare show() as returning void. Change void show() to LineDatabase show().
Also, try to keep variable and type names lower-case. Typical convention is to use capitalized names for template parameters, so it is a bit confusing to read.
There are 4 options.
The simplest option is to change the return type of show and uncomment your return, however this will be returning the map by value which will involve a copy and could (depending upon size) be very inefficient (possibly dangerous, depending upon LineDatabase's copy operator).
LineDatabase show()
{
LineDatabase Entry;
// .... ommited
return Entry;
}
The 2nd option is to do as was suggested by user258808 and create a new object then return it by pointer, the issue with this approach is that your client would have to know to call delete on this pointer when finished otherwise you would be creating a leak.
The 3rd option is to have Entry as a field of ReadMap and then return a reference. This is my personal preference as it imposes the least burden on the client, however it may also require you to 'reset' the Entry before each new run.
Something like this
class ReadMap
{
string fileName;
LineDatabase Entry;
public:
//constructors and destructor
ReadMap(){fileName="blank.txt";}
ReadMap(string name){fileName=name;}
~ReadMap(){}
//Function to print out visible list
LineDatabase& show()
{
int LineNumber=100;
string buffer;
ifstream myfile (fileName.c_str() );
while (myfile.good())
{
myfile >> LineNumber >> ws;
getline (myfile, buffer);
Entry.insert(pair<int, string>(LineNumber, buffer));
cout <<buffer << endl;
}
return Entry;
}
};
The issue with this is that it exposes your internal state to modification, it is possible to return a const reference but then the client cannot modify the Map.
Finally, you could do as was suggested by bodes. However this requires that the client passes in a Map for you to work on.
Your choice will depend on how much work you would like to require your client to do as well as what kind of constraints you need and/or do not need to place on the data structure.

c++ .h and .cpp files - about methods

HI.
How can I define a bool method in .h file and work with it in the cpp file?
I have
my.h
#include <string>
public class me;
class me
{
public:
me();
private bool method(string name); //it is ok??
}
my.cpp
#include 'my.h';
me::me()
{
method(string name); //can i do this? isn't there another alternative?
}
method (String name)
{
cout<<"name"<<endl;
}
is not working.why?
I suggest you learn the basics of C++ from a tutorial
my.h
#include <string>
class me
{
public:
me();
bool method(std::string name) const;
};
my.cpp
#include 'my.h';
me::me()
{
}
bool me::method(std::string name)
{
std::cout << name << std::endl;
}
As written, there is no need for me::method to be a member function (it could be a static).
Numerous little fixes there. I get the sense that you are coming from C# (possibly java). Read up on the differences. Google has good sources :)
There are a number of issues with your code.
my.h
#include <string>
// public class me; // Absolutely not needed. From which language did you get this?
class me
{
public:
me();
private: // You need the colon here.
bool method(string name); //it is ok?? // No. The class is called std::string. You should pass it by const-reference (const std::string& name);
}
my.cpp
#include 'my.h';
me::me()
{
// `name` is undefined here. You also don't need to specify the type.
//method(string name); //can i do this? isn't there another alternative?
method("earl");
}
// method (String name) // See previous comment about const-reference and the name of the class. Also note that C++ is case-sensitive. You also need to specify the return type and the class name:
bool me::method(const std::string& name)
{
// cout<<"name"<<endl; // Close...
std::cout << "My name is " << name << std::endl;
return true; // we are returning a `bool, right?
}
You'll also need to call your code:
int main()
{
me instance_of_me;
return 0;
}
I suggest you take a look for a good C++ tutorial and some reading material.
Answers to questions in the comments:
could you please tell me why do I need to pass std::string through reference?
This question has already been asked (more than once) on StackOverflow. I recommend this answer.
And what is with me mo?
In hindsight mo was a terrible choice for a variable name. instance_of_me may have been a better choice. This line constructs an instance of me, calling the constructor (which in turn calls method("earl"))
You meant me method("hello"); in the main()
I certainly did not!
You declared method as a private member function. This method cannot, therefore, be called from outside the class.
First of all, you have missed : after private
Second, if method (String name) in the cpp file should be the method (String name) from your class, it must be:
bool me::method(std::string name)
{
// ...
}
Third, if you want this bool me::method(std::string name) to be different function, a global one, not from you class, it must be:
ret_type method(std::string name)
{
// ...
}
And, fourth,
cout<<"name"<<endl;
will pring the string (literal) "name". If you want to print the variable name, use it without the quotes:
std::cout<< name <<endl;
I'd recommend you to get a book
Ah, and this one:
me::me()
{
method(string name); //can i do this? isn't there another alternative?
}
method(string name) - this is not valid syntax. It should be something like:
me::me()
{
string name;
// do something with name
method( name ); // if "method" is a method, for real
}

C++ - syntax for defining/instantiating strings

I am very new to C++ and still trying to learn syntax and best practices.
I've defined a method with a single parameter:
void foo(const std::string& name)
1) Is this a proper parameter declaration for a function that will be taking in a string defined by the user in, for example, a main method?
2) If this is proper/recommended syntax, what would an instantiation of a sample parameter look like?
Yes, that is the correct syntax. You can call it and provide parameters several different ways:
With a string literal:
foo("bar");
With a string variable:
std::string b = "bar";
foo(b);
With the result of a function return type string:
std::string quux();
foo(quux());
With a char* variable:
int main(int argc, char const* argv[]) {
foo(argv[0]);
}
I'm not sure if I fully understand your question, but I'll try to clarify it.
You use the terminology 'method'. I'm assuming that your method is encapsulated in a class? If so, then :-
In your header file (eg. source.h),
class dog
{
...
public:
void foo(const std::string &name);
...
};
In your source file (eg. source.cpp)
void dog::foo(const std::string &name)
{
// Do something with 'name' in here
std::string temp = name + " is OK!";
}
In your 'main' function, you can instantiate your 'dog' class, and call the 'foo' function like :-
void blah()
{
dog my_class;
my_class.foo("Testing my class");
}
If you want a function (ie. a 'method' that is not encapsulated within a class), then what you have is correct.
In your source file (eg. source.cpp)
void foo(const std::string &name)
{
// Do something with 'name' in here
std::string temp = name + " is OK!";
}
If you want to be able to call your function from outside that particular source file, you'll also need to forward declare your function in a header file.
In your header file (eg. source.h)
void foo(const std::string &name);
To call your function,
void blah()
{
foo("Testing my class");
}
Hope this helps!
1)
It is a proper parameter declaration if function foo() doesn't mean to change the string. The 'const' keyword is used to signify that the string won't be changed by the receiver.
If you write code in foo() which modifies the string you will get compiler error/warning.
2)
std::string theString = "Hello";
foo( theString );
Is this a proper parameter declaration for a function that will be taking in a string defined by the user in, for example, a main method?
Yes.
#include <string>
using namespace std;
void foo(const string& name)
1) Yes, that's a very good way to do it if you only need to read the string in the function.
2) There is no instantiation going on?
1) For most functions, it would be a fine signature. However, since you mentioned main(), there are only two valid signatures:
int main()
int main(int argc, const char* argv[])
...as you can see, you have to use C-style strings due to C-legacy compatibility (and efficiency)
2) Not sure I understand your second question, but since std::string has a constructor that takes a const char*, you can just say:
foo("hello");
or:
std::string input;
std::cout << "Enter some text: ";
std::cin >> input;
foo(input);