Pregunta

I'd like to create a self-defined file stream class that I can use to print and read formatted(text) and unformatted(binary) datas. The shift operators(<< and >>) already exist, as well as write and read members of filestreams, but I would like to use the shift operator << only, and create unformatted output if the stream is opened in binary mode, and formatted otherwise.

The code I wrote does not work correctly at least for strings and chars( and cstrings):

class mixstream:public fstream {

public:

//some constructors and public functions in the code

template <class T> mixstream& operator<< (T&& param)
{
    if (openmode() & ios_base::binary)
        write((char *) &param, sizeof(param)); //binary write-out

    else 
        fstream::operator<<(param); //non-binary write out

    return *this;
}

template <class T> mixstream& operator>> (T&& param)
{
    if (openmode() & ios_base::binary) 
        read((char *) &param, sizeof(param)); //binary read-in

    else 
        fstream::operator>>param; //non-binary read-in

    return *this;
}
};

The problem is probably somewhere around ostream's shift operator, so that ostream's << and >> operators are not overloaded with chars, cstrings and strings.

Could you point out where should I modify my code and what should I replace to what?

I would also appreciate if you give advices and show a good practice for my purpose, so workarounds are also accepted - if they are elegant.

¿Fue útil?

Solución

Based on another SO question titled "Problem with overriding “operator<<” in class derived from “ostream”" I can achieve my aims.

  1. As Johannes Schaub - litb suggested on the link above, I don't use shift operator as member function, I will use it as free functions. Therefore I have to define a new member of the class that stores whether the file was opened in binary mode or not.
  2. The move semantics seems to be necessary. Without that, the string, char and cstring outputs not working correctly (at least, working differently than expected :) ).
  3. UncleBens' answer with the tweaks looks to be good.

First, define the class:

class mixstream:public fstream
{
    bool binmode;

public:
    //constructors
    explicit mixstream() {};

    explicit mixstream ( const char * filename, ios_base::openmode mode = ios_base::in | ios_base::out) :
    fstream(filename, mode)
    {
        if (mode & ios_base::binary)
            binmode = true;

        else
            binmode = false;

    };

    void open(const char *_Filename, ios_base::openmode _Mode = ios_base::in | ios_base::out, int _Prot = (int)ios_base::_Openprot)
    {
        fstream::open (_Filename, _Mode, _Prot);

        if (_Mode & ios_base::binary)
            binmode = true;

        else
            binmode = false;

    }

    bool get_binmode() const {return binmode;}
}

And then define the overloaded insertation and extractation operator:

template <class T> mixstream& operator<< (mixstream& stream, const T&& param)
{
    if (stream.get_binmode())
        stream.write((char *) &param, sizeof(param));

    else
        (fstream&)stream << param;

    return stream;
}

template <class T> mixstream& operator>> (mixstream& stream, const T&& param)
{
    if (stream.get_binmode())
        read((char *) &param, sizeof(param));

    else
        ostream::operator>>param;

    return *this;
}

So then I can use my new stream in a form:

int main(int argc, char *argv[]) {

    mixstream bin_or_not;
    if (true) //some condition
        bin_or_not.open("file.dat",ios_base::out | ios_base::binary);

    else
        bin_or_not.open("file.dat",ios_base::out);


    char testcs[] = "testsc";
    string tests("tests");
    int testn = 10;

    bin_or_not << 10 << testn << "testcs" << testcs << tests; 

    return 0;
}

Comments and answwers are still welcomed as suggestions for improvement.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top