大多数时候,如果人们希望将自己的课程提供给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
类如上例所示,并完成了我需要做的所有事情?
答案 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();
至于你为什么要这样做:
结果是一个真正的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;
}
};
这适用于hex_stream
,因为它在此处定义:
hex_stream ss(std::cout, true);
foo f{ 1, false };
ss << f;
生成输出:0x310x2c0x200x660x610x6c0x730x65
在这种情况下,0x31是1
,0x2c是逗号,0x20是空格,0x660x610x6c0x730x65
是false
的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;
}