Creating a class that contains a string object to hold the text of a file

So I have this question, and was wondering how to get the program to read the contents of the file as i'm getting a blank screen. What am I missing here?

Question: Write a program in which you create a Text class that contains a string object to hold the text of a file. Give it two constructors: a default constructor and a constructor that takes a string argument that is the name of the file to open. When the second constructor is used, open the file and read the contents of the file into the string member object. Add a member function contents() to return the string so that you can display it. In main(), open a file using Text and display the contents.

This is the code I have so far!
Thanks!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text() //What do I put in here?
     {
     ifstream f();
     string line;
     while (getline(f, line))
            


The code is incomplete, but I feel like i'm missing something!
Just have the second constructor have a parameter of type string

1
2
3
4
5
Text(string filename)
{
  //Read file, etc, store the content in your 'text' variable
  ...
}
for example you could do something like this

1
2
3
4
5
6
7
8
9
10
11
12
Text(std::string filename) 
{
	std::ifstream readFile(filename);
	std::string currentLine;

	while (!readFile.eof()) // if its not at the end of file(.eof)
	{
		std::getline(readFile, currentLine);
		std::cout << currentLine << "\n" << std::endl;
	}

}

Last edited on
I don't recommend looping over eof, but the idea is correct.
You could loop using while (std::getline(readFile, currentLine){...
The loop will execute as long as getline is able to read a line from the file.

I don't know what the file looks like, so I can't tell you what the best way is of pulling out the contents, but just make sure you append that to something if you want to save it after reading it.

Alright, so this is what I got so far, I got an error and how do I put in my OWN text file into the program? I've tried before and I keep getting the same errors.

Here is what I got so far

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text(string filename)
     {
     ifstream f(filename); //No matching function for call to 'std::basic_ifstream<cha>::basic_ifstream(std..)
     string currentLine;
     while (getline(f, currentLine))
     {
            cout << currentLine << "\n" << endl;
     }
     }
};
closed account (48T7M4Gy)
It might be a good point to refer back to the question in the OP. All you are being asked to do is to handle text in the form of a single string, not a line or whole slab of text. The only thing on the persistent store - the text file - is the class member called 'text', which should be private: BTW

So, just use the following modified sample from the tutorial here as a model:
1
2
3
4
5
6
7
8
9
10
11
12
13
// reading a text file
  ifstream myfile (filename); // <-- 
  if (myfile.is_open())
  {
    while ( myfile >> text ) // <--
    {
      cout << text << '\n'; // <-- you don't really need this
    }
    myfile.close();
  }

  else cout << "Unable to open file"; // <-- maybe return this as an error message
}


Remember that the OP question has a constructor and a method called contents() depending on whether the text string is being read from or into the file. You can sort out which is which.

(You may also need to make sure the file-based constructor 're-builds' and returns a Text object rather than just a string. That is what is supposed to happen normally where full serialization is meant to happen but the question isn't crystal clear on that so maybe just play the teachers game on that.)
Ok, so I took the code you posted above Kemort and added it into mine, however I am getting errors still.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text(string filename)
     {
     ifstream f(filename);//Error:no matching function for call to 'std::basic_ifstream<char>::basic_ifstream..
     if (f.is.open()) //Error:std::ifstream has no member name 'is'
     {//No matching function for call to 'std::basic_ifstream<cha>::basic_ifstream(std..)
     while ( f >> text )
     {
        cout << text << '\n';
     }
     f.close();

     }
     else cout << "Unable to open file";
};//Error: expected unqualified-id at end of input & expected '}' at end of input 


Shouldn't I have an int main() section to print everything out and not within the class itself? All of my problems are stemming from reading the input file.
Line 16: An ifstream constructor that accepts a string was introduced on C++11. Either turn on the C++11 flag in your compiler, or use
 
  istream (f(filename.c_str());


Line 17: Typo. You want is_open(), not is.open.

Line 26.1: You're missing a close } to terminate the constructor.

Shouldn't I have an int main() section to print everything out

Yes.
closed account (48T7M4Gy)
Shouldn't I have an int main() section to print everything out and not within the class itself? All of my problems are stemming from reading the input file.


Of course you do! Experience will show you how to handle code snippets and this is an example.

I get the impression you don't quite have a handle on classes and what main does.

You write a class, in this case to invent a new data type rather than just playing with int's all your career.

So once you invent one you can exercise it by writing a (main) program to test it and run programs that now use ints and objects created from your new data type called Text. :)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <fstream>
#include <iterator>

struct Text
{
    // Text() = default ; // explicitly defaulted default constructor
    Text() {} // legacy C++ 

    /* explicit */ Text( std::string file_name )
    {
        // std::ifstream file(file_name) ; // open the file for input
        /* or */ std::ifstream file( file_name.c_str() ) ; // open the file for input (legacy C++)

        // txt = { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() ; }
        /* or */
        {
           char c ;
           // for each character read from the file, including white-space characters
           while( file.get(c) ) txt += c ; // append the character to the string
        }
    }

    const std::string& contents() const { return txt ; }

    private: std::string txt ;
};

int main()
{
    std::cout << Text( __FILE__ ).contents() ; // _FILE__ - name of this file
}

http://coliru.stacked-crooked.com/a/90cb5a45f39016dc
Last edited on
I apologize about that Kemort, i'm very new to C++ and programming in general. As for the code, I changed a couple things from the last time, removed the if and else statements and added a main section to print it out. Is this correct? I should probably remove the cout under the while loop since i'm not supposed to print in the class itself.

Below is what I have updated, let me know if i'm in the right direction and or I should go back to another route that we were discussing earlier. Everything compiles and runs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text(string filename)
     {
     string line;
     ifstream f(filename.c_str());
     while (getline(f, line))
     {
        cout << text << '\n';
     }
     }
};

int main()
{
    Text a;
    cout << " " << a.contents() << endl;
}
Oh wow JLBorges, I didn't realize you had just posted that. Guess I didn't see it because I didn't refresh the page when I posted again.

What I don't understand in that is what line 21 does.
the 'txt += c' I realizes says it appends the character to the string, but what exactly does that mean itself (i'm really sorry, i'm very new to this and i'm sure this seems like a cake walk to you guys). I'm not sure what the '+=' sign means?

Thanks
x += c; is a short-hand way of writing x = x + c;. Technically speaking, += is a separate operator from + and =, but it is expected that doing += will exhibit similar behavior as using both + and = separately.

http://en.cppreference.com/w/cpp/language/operators
Excellent JayhawkZombie, that makes sense now.

So, now that I understand what that operator means,

I removed the cout from line 20, and added in the text += line;

Would this be correct, or is there still some changes that I need to make?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text(string filename)
     {
     string line;
     ifstream f(filename.c_str());
     while (getline(f, line))
     text += line;
     }
};

int main()
{
    Text a;
    cout << " " << a.contents() << endl;
}
Line 25: You're invoking the default constructor which does nothing. If you want to read from a file, then you need to use the second constructor which accepts a file name.
 
  Text a ("somefile.txt");

I would indent your code, so it's a little easier to read. I generally always put my loops within braces, but for one-liners you don't need that.
1
2
3
4
5
6
7
Text(string filename)
{
  string line;
  ifstream f(filename.c_str());
  while (getline(f, line))
    text += line;
}

Do you want to read in the file exactly as it appears? If so, you should do what JLBorges showed above and read the file character-by-character so you pick up every whitespace character (including newline characters).

Also like JLBorges showed above, you should use default if you wish to have the default constructor made for you:
 
Text::Text() = default;

It isn't explicitly necessary, but it is in line with the new standard as of C++11.
http://en.cppreference.com/w/cpp/keyword/default

Also, close the file stream when you're finished with it f.close().

JLBorges's example is a very good one to follow. The only line you might have trouble with is this one
txt = { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() ; }, to which he presented an alternative.
This is fine (except that there would be a spurious new line at the end if the file did not end with a new line):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Text
{
    Text() {}

    /* explicit */ Text( std::string file_name )
    {
        std::ifstream file( file_name.c_str() ) ;
        std::string line ;
        while( std::getline( file, line ) ) txt += line + '\n' ; // note: add a new line at the end
    }

    const std::string& contents() const { return txt ; }

    private: std::string txt ;
};

http://coliru.stacked-crooked.com/a/61a2d09cdebd8fd1
So, I made the changes accordingly as JLBorges suggested (haven't added in the f.close yet, but will after). So everything compiles, and the text within the textfile that I put into the program prints out. Is this correct?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Text {
    string text;
public:
    Text() {}
     string contents()
     {
        return text;
     }
     Text(string filename)
     {
     string line;

     ifstream f(filename.c_str());

     while (getline(f, line))
     text += line + '\n';
     }
     const string& contents() const
     {
         return txt;
     }
private: string txt;
};

int main()
{
    cout << Text("TMA2Q3.txt").contents() << endl;
}
Last edited on
Line 7, 27: You have both txt and text defined in your class. You only need one.

Line 23: You have defined contents() twice. One returns txt. One returns text. One of these is not needed. Since line 21 appends to txt, contents() at line 10 will return an empty string since you never modify txt.

Remove line 7 and lines 10-13.

Right. I forgot to remove the other text! Thanks Anon!
Topic archived. No new replies allowed.