Reputation: 199
I'm struggling with streams. I would like to have FileWriter that writes MyObject data to file or to a stringstream. I don't want the interface of write() to take the file path or the stringstream becouse I may have other concrete writers that serialize to some different devices (i.e. socket). So I need to pass the file path or the stringstream to the FileWriter constructor. I need to have a stringstream as an alternative to a filePath so that I can easily implement unit testing.
Here is a sketch of the classes I have described:
class IObjectWriter {
virtual void write(MyObject& o) = 0;
};
class FileWriter : public IObjectWriter {
FileWriter(const std::string& filePath) {
std::ofstream os(filePath, std::ios::out);
// assign in some way os to stream member variable
}
FileWriter(std::ostringstream& so) {
// assign in some way os to stream member variable
}
void write(MyObject& o) override {
stream << o.getSomeValue();
}
private:
std::ostream stream;
};
The problem I could not solve is to "assign" the ofstream and ostringstream to the ostream member so that the write() call can write independently on file or stingstream.
Problems I've run into:
Possible solutions or ideas:
Upvotes: 0
Views: 749
Reputation: 596497
Why can't you simply have two separate classes - FileWriter
that writes to an ofstream
, and StringWriter
that writes to an ostringstream
? Let the user decide which type of writer it wants to use, eg:
class FileWriter : public IObjectWriter {
public:
FileWriter(const std::string& filePath) : stream(filePath) { }
void write(MyObject& o) override {
stream << o.getSomeValue();
}
private:
std::ofstream stream;
};
class StringWriter : public IObjectWriter {
public:
StringWriter(std::ostringstream &os) : stream(os) { }
void write(MyObject& o) override {
stream << o.getSomeValue();
}
private:
std::ostringstream &stream;
};
FileWriter fw("path");
fw.write(obj);
std::ostringstream oss;
StringWriter sw(oss);
sw.write(obj);
You could then reuse some code by adding a common base class, eg:
class StreamWriter : public IObjectWriter {
public:
StreamWriter(std::ostream& os) : stream(os) { }
void write(MyObject& o) override {
stream << o.getSomeValue();
}
private:
std::ostream &stream;
};
class FileWriter : public StreamWriter {
public:
FileWriter(const std::string& filePath) : StreamWriter(ofs), ofs(filePath) { }
private:
std::ofstream ofs;
};
class StringWriter : public StreamWriter {
public:
StringWriter(std::ostringstream &oss) : StreamWriter(oss) { }
};
But, in that case, you may as well just use StreamWriter
by itself, and let the user pass in whatever ostream
-derived object it wants to write to, eg:
std::ofstream ofs("path");
StreamWriter sw1(ofs);
sw1.write(obj);
std::ostringstream oss;
StreamWriter sw2(oss);
sw2.write(obj);
Upvotes: 3