我怎样才能使用operator&lt;&lt;使用&lt; <! - 将文件对象提供给我的类

时间:2017-02-25 23:02:08

标签: c++ c++14

大多数时候,如果人们希望将自己的课程提供给friend对象(例如ostream),则会将其设为cout。但对我来说情况并非如此。我需要operator<<的重载,这可以让我做这样的事情:

std::fstream fileobj(".\example.file", std::ios::in | std::ios::binary);
AraHaan::hexstream hexstrm;
hexstrm << fileobj; //<--  itterates through the file object and hex arrays the data in it.

问题是我不知道如何做到这一点。 hexstream的当前类代码如下:

#ifndef HEXSTREAM_DEFINED
#define HEXSTREAM_DEFINED
#include "basic_hexstream"

namespace AraHaan {
    class hexstream: public AraHaan::basic_hexstream {
    };
}

#endif

basic_hexstream

#ifndef BASIC_HEXSTREAM_DEFINED
#define BASIC_HEXSTREAM_DEFINED
#include <sstream>
#include <iomanip>

namespace AraHaan {
    class basic_hexstream {
    private:
        std::stringstream base_hexstream;
        bool data_cleared;
        bool append0x, writehexseparater;
    public:
        void AddCharacter(int character) {
            data_cleared = false;
            if (append0x) {
                if (writehexseparater) {
                    base_hexstream << "0x" << std::uppercase << std::setfill('0') <<
                        std::setw(2) << std::hex << static_cast<unsigned short>(character) << ", ";
                } else {
                    base_hexstream << "0x" << std::uppercase << std::setfill('0') <<
                        std::setw(2) << std::hex << static_cast<unsigned short>(character);
            }
            } else {
                if (writehexseparater) {
                    base_hexstream << std::uppercase << std::setfill('0') <<
                        std::setw(2) << std::hex << static_cast<unsigned short>(character) << ", ";
                } else {
                    base_hexstream << std::uppercase << std::setfill('0') <<
                        std::setw(2) << std::hex << static_cast<unsigned short>(character);
                }
            }
        }
        void setoptions(bool append_0x, bool writehexseparator) {
            append0x = append_0x;
            writehexseparater = writehexseparator;
        }
        const std::string str() {
            return base_hexstream.str();
        }
        void clear() {
            data_cleared = true;
            base_hexstream.clear();
            base_hexstream.str("");
        }
        /*
        TODO: make this work for ifstream, fstream, and FILE* file objects.
        ex.
            std::fstream fileobj(".\example.file", std::ios::in | std::ios::binary);
            AraHaan::hexstream hexstrm;
            hexstrm << fileobj; //<  itterates through the file object and hex arrays the data in it.
        */
        void operator<< (void* cool) {}
        void operator<< (int character) {
            // Note: Clearing the hexstream after every character is the user's responsibility
            //     if ran in a for loop that can dublicate the information that is if the data from
            //     the hexstream is obtained and added to a string after every itteration.
            AddCharacter(character);
        }
        basic_hexstream() {}
        ~basic_hexstream() {
            // clears the data just in case.
            // This makes clearing this manually optional.
            if(!data_cleared) {
                clear();
            }
        }
    };
}

#endif

但是,我需要实现运算符&lt;&lt;在basic_hexstream类中正确地为此工作,不仅可以在某种程度上对文件对象有效,而且当某人传入一个被转换为int的角色时。 如何使用运算符&lt;&lt;使用&lt;&lt;将文件对象提供给hexstream类如上例所示,并完成了我需要做的所有事情?

2 个答案:

答案 0 :(得分:1)

如果我要这样做,我会采取一种截然不同的方法。

我没有编写类似于整个流的类,并且使它与现有的流不兼容,而是编写了过滤streambuf类,在通过的过程中将数据转换为十六进制:

class hex_buf : public std::streambuf {
    std::streambuf *buffer;
    bool use_prefix;
public:
    typedef std::char_traits<char> traits_type;
    typedef traits_type::int_type  int_type;

    hex_buf(std::ostream &os, bool use_prefix) : buffer(os.rdbuf()), use_prefix(use_prefix) {}

    int_type overflow(int_type c) {
        static const char chars[] = "0123456789abcdef";

        if (use_prefix) {
            buffer->sputc('0');
            buffer->sputc('x');
        }
        unsigned char ch = (unsigned char)c;
        buffer->sputc(chars[ch >> 4]);
        return buffer->sputc(chars[ch & 0xf]);
    }
};

然后我们可以创建一个附加到现有流的流类,但添加过滤streambuf到混合:

class hex_stream : public std::ostream { 
    hex_buf output;
public:   
    hex_stream(std::ostream &os, bool use_prefix = false) : output(os, use_prefix), std::ostream(&output) {}
};

现在,我已经写了hex_stream来将现有的ostream作为目的地。如果你愿意,让它自己构造一个ostream很简单(例如,你传递一个名字,它构造一个fstream,或者你没有传递任何东西,它构造一个字符串流)。

要使用它,我们不(通常)直接使用hex_buf类 - 我们只使用hex_stream,并将其附加到某个现有流:

    hex_stream s(std::cout);  
    s << "1234";

    hex_stream t(std::cout, true);  
    t << "1234";

有了这个,将一些其他流复制到这种类型的流可以像我们使用任何其他流一样进行:

hex_stream h(std::cout);   
std::ifstream infile("test.txt");

h << infile.rdbuf();

至于你为什么要这样做:

  1. 代码实际上更短更简单。
  2. 结果是一个真正的ostream,所以基本上所有与现有ostream一起使用的东西也可以使用它。例如,考虑无数现有的流插入运算符。例如,像这样:

    struct foo {
        int a;
        bool b;
    
        friend std::ostream &operator<<(std::ostream &os, foo const &f) {
            return os << std::boolalpha << f.a << ", " << f.b;
        }
    };
    
  3. 这适用于hex_stream,因为它在此处定义:

    hex_stream ss(std::cout, true);
    
    foo f{ 1, false };
    
    ss << f;
    

    生成输出:0x310x2c0x200x660x610x6c0x730x65

    在这种情况下,0x31是1,0x2c是逗号,0x20是空格,0x660x610x6c0x730x65false的ISO-8859编码,以十六进制表示。

    换句话说,不仅现有的流插入运算符,而且用户提供的重载插入运算符都可以工作 - 所以(正如我们用std::boolalpha所示)执行现有的流操作符。

    有一种替代方法可以达到更合适的条件。您可以创建一个将输出编码为十六进制的codecvt构面,而不是创建过滤流缓冲区。这已经很长了,所以我现在不会为此包含代码。

答案 1 :(得分:0)

您可以使用其中一种方法。下面,您有两个简单流示例,它们从fstream获取数据并在控制台中输出。

示例1(运算符&lt;&lt;成员函数)

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

class TextStream
{
public:
    string getText() const;
    TextStream& operator<<(fstream& stream);

private:
    string text;
};

string TextStream::getText() const
{
    return text;
}

TextStream& TextStream::operator<<(fstream& stream)
{
    while (true)
    {
        string line;
        if (!std::getline(stream, line)) break;
        line += '\n';
        text += line;
    }

    return *this;
}

int main(int argc, char **argv)
{
    fstream file1("temp1.txt");
    fstream file2("temp2.txt");

    TextStream ts;
    ts << file1 << file2;
    cout << ts.getText() << endl;

    file1.close();
    file2.close();

    return 0;
}

示例2(运营商&lt;&lt; friend功能)

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

class TextStream
{
public:
    string getText() const;
    void append(const string& s);

    friend TextStream& operator<<(TextStream& textStream, fstream& fileStream);

private:
    string text;
};

string TextStream::getText() const
{
    return text;
}

void TextStream::append(const string& s)
{
    text += s;
}

TextStream& operator<<(TextStream& textStream, fstream& fileStream)
{
    while (true)
    {
        string line;
        if (!std::getline(fileStream, line)) break;
        line += '\n';
        textStream.append(line);
    }

    return textStream;
}

int main(int argc, char **argv)
{
    fstream file1("temp1.txt");
    fstream file2("temp2.txt");

    TextStream ts;
    ts << file1 << file2;
    cout << ts.getText() << endl;

    file1.close();
    file2.close();

    return 0;
}