0

The exercise says:

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 into the string member object. Add a member function contents() to return the string so (for example) it can be printed. In main( ), open a file using Text and print the contents.

This is the class that I wrote:

class Text {
    string fcontent;

    public:
        Text();
        Text(string fname);
        ~Text();

        string contents();
};

I haven't understood everything of this exercise. It asks to create a function contents(), that returns a string, but it doesn't says what the function has to do...
Neither what the default constructor has to do.
Could someone help me?

Overflowh
  • 1,052
  • 6
  • 18
  • 39
  • 2
    The function has to return the string; it says that. – Oliver Charlesworth Apr 02 '12 at 18:23
  • 1
    `contents()` should return the contents of the file when Text is instantiated with the second constructor. – Niklas B. Apr 02 '12 at 18:23
  • See my old [answer](http://stackoverflow.com/a/2602258/179910) about reading a file into a string, as well as my old [blog post](http://coderscentral.blogspot.com/2011_03_01_archive.html) about how to read from a file in general. At the risk of sounding a bit nasty, at least in my opinion, the code in @GuyGreer's answer should be avoided. – Jerry Coffin Apr 03 '12 at 04:20
  • @Jerry Coffin- Would like to understand what pitfalls do you see in GuyGreer's answer below. IS there any efficient/optimal way of reading file content in string what the OP asks? – goldenmean Apr 03 '12 at 14:35
  • @goldenmean: did you look at what I linked? It has a couple of much more straightforward methods. The primary pitfall is that it's extremely roundabout at nearly everything it does, so it's extremely fragile at best. It's basically attempting to get the "zig" bugs to compensate for the "zag" bugs in the hope of producing a zig-zag that ends up in the right place. I'm advocating drawing a straight line instead. – Jerry Coffin Apr 03 '12 at 14:39
  • @Jerry Coffin - Thanks for details. Yes I had looked at your stringstream buffer << ifstream.rdbuf() solution. – goldenmean Apr 03 '12 at 14:51

1 Answers1

1

The function has to return the contents of the file, which is stored (in your case) in fcontents.

    string Text::contents()
    {
      return fcontent;
    }

The default constructor doesn't have to do anything in this case.

    Text::Text(){}

EDIT: Seeing how many comments there are below with new problems, I'm going to recap and answer the rest of the questions here.

in Text.h you have:

    #ifndef TEXT_HH
    #define TEXT_HH

    #include <string> //[1] 

    class Text {
        std::string fcontent;//[2]
    public:
        Text();
        Text(std::string fname);
        ~Text();

        std::string contents();
    };

    #endif

and Text.cpp has

    // Text.cpp

    #include "Text.h"
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <string>

    using namespace std;

    Text::Text() {}

    Text::Text(string fname) {
        fstream f;
        f.open(fname.c_str(), ios::in);//[3]

        //[4]
        std::stringstream stream;
        while(true)
        {
            char buffer[1000];
            f.getline(buffer, 1000);
            if(f.good())
            {
                //This actually adds an extra newline at the end
                stream << buffer << '\n';
            }
            else
            {
                break;
            }
        }
        fcontent = stream.str();
        //remove extra newline
        fcontent.erase(fcontent.begin() + fcontent.size() - 1);
        f.close();//This is technically unnecessary, but not bad either
    }

    string Text::contents() {
        return fcontent;
    }

    Text::~Text() {}//[5]

Point 1: The header file <string> contains the class definition for std::string, the C++ string. This should not be confused with <cstring> which contains functions for manipulating C strings (const char *, const char[], etc).

Point 2: The string class exists in the ::std namespace, which means we have to either use std::string every time we want that class or use using namespace std; to pull this class into the global scope. In the header file we prefer the former method because the using declaration doesn't go away, which means that the namespace will be changed for every header and source file that includes this one, which we want to avoid in general (ie. always). In the cpp file however, there is no problem using the using declaration and we do so.

Point 3: fstreams take a C string as the filename parameter, we can get the corresponding C string from a C++ string with the call c_str(). This returns a const char *.

Point 4: To read the whole text file into a string is less obvious than it seems because the way streams deal with eof (end-of-file) and state-checking stuff. In short it will read one more time than you want it to (I know, wanting is subjective, but is close enough I think) before setting the eof flag. That's why the state is checked after calling get and before adding what's been read to our stringstream. Streams are a fairly elaborate topic so I won't go into it in more detail here.

Point 5: Destructors on objects (non-pointers, like our fcontents is) are called automatically, so we don't need to do anything to make sure that our fcontents string is destroyed when our Text object is destroyed. When we allocate something dynamically with new that's when we have to worry about calling delete on it when we want to destroy it.

SirGuy
  • 10,222
  • 2
  • 32
  • 63
  • Yeah, I do this just like you. But in the .h file, the compiler gives me an error saying that "'string' does not name a type", but I have included in cpp file... – Overflowh Apr 02 '12 at 18:36
  • Include it in your .h file so it'll be know there *and* in your .cpp file. – DerMike Apr 02 '12 at 18:38
  • 2
    you want to include ``, `` is for C strings where you want C++ strings (the former). These strings exist in the std namespace which means to use it you also have to either specify `using namespace std;` or use `std::string` everywhere you use it – SirGuy Apr 02 '12 at 18:39
  • @GuyGreer: Ok, done. Here the code wroten 'till now. There's something that doesn't work: http://pastebin.com/cAVzFbB8 – Overflowh Apr 02 '12 at 18:47
  • 1
    Have you also added the include in your Text.h file? Note that in header files you usually don't want to use a `using namespace n;` declaration because it will affect every file that includes it (which in general is not what you want) so use std::string in your header file. If that's not the problem you're going to have to be more specific than _something_ doesn't work. – SirGuy Apr 02 '12 at 18:51
  • Yeah, I already made all that you said. Here the code of the .h and .cpp: http://pastebin.com/0jKQNFNk | http://pastebin.com/HcHjtZYV The compiler gives me this error: "no matching function for call to 'std::basic_fstream >::open(std::string&, const std::_Ios_Openmode&)'|" – Overflowh Apr 02 '12 at 18:59
  • 1
    fstreams take C strings for the filename, to get the C string from a C++ std::string call c_str as in: `f.open(fname.c_str(), ios::in);` – SirGuy Apr 02 '12 at 19:02
  • @GuyGreer: Now it works... I don't know that fstream take a C-style string. However, the destructor? It's enough to write `delete fcontent;`? – Overflowh Apr 02 '12 at 19:08
  • 1
    No, only delete pointers that have been allocated with new. Objects (non-pointers like your fcontents) will have their destructors called when they need to be, in this case when `Text::~Text()` is called which will be done automatically when it goes out of scope – SirGuy Apr 02 '12 at 19:11
  • @GuyGreer: Ok, understood. The destructor automatically destroys the object when the go out-of-scope. Now the program compiles and works enough, but how it's possibile to put the entire content of a textfile in a single variable? Is will hold just the last line of that file, right? – Overflowh Apr 02 '12 at 19:17
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/9635/discussion-between-unnaturhal-and-guygreer) – Overflowh Apr 03 '12 at 11:06