I have run into trouble trying to implement functionality for serializing some classes in my game. I store some data in a raw text file and I want to be able to save and load to/from it.
The details of this, however, are irrelevant. The problem is that I am trying to make each object that is interesting for the save file to be able to serialize itself. For this I have defined an interface ISerializable, with purely virtual declarations of operator<< and operator>>.
The class Hierarchy looks something like this
-> GameObject -> Character -> Player ...
ISerializable -> Item -> Container ...
-> Room ...
This means there are many possible situations for serializing the objects of the different classes. Containers, for instance, should call operator<< on all contained items.
Now, since operator>> is virtual, i figured if I wanted to serialize something that implements the functionality defined in ISerializable i could just do something like
ostream & Player::operator<<(ostream & os){
Character::operator<<(os);
os << player_specific_property 1 << " "
<< player_specific_property 2 << "...";
return os;
}
and then
ostream & Character::operator<<(ostream & os){
GameObject::operator<<(os);
os << character_specific_property 1 << " "
<< character_specific_property 2 << "...";
return os;
}
but I quickly learnt that this first attempt was illegal. What I'm asking here is how do I work around this?
I don't feel like implementing a function manually for each class. I guess I'm looking for something like the super functionality from Java.
Any help is appreciated.
-- COMMENTS ON EDIT ------------
Alright, last time I was in a hurry when I was writing the question. The code is now more like it was when I tried to compile it. I fixed the question and the problem I had was unrelated to the question asked. I'm ashamed to say it was caused by an error in the wake of a large refactoring of the code, and the fact that the operator was not implemented in every base class.
Many thanks for the replies however!
The problem is not in your attempt to call a virtual function non-virtually. The problem is this line: os = Character::operator<<(os);. That is an assignment, but std::ostream doesn't have an operator=.
You don't need the assignment anyway. The stream returned is the same stream as the stream you pass in. The only reason it's returned is so you can chain them.
Hence the fix is to just change the code to
ostream & Player::operator<<(ostream & os){
Character::operator<<(os);
os << player_specific_property 1 << " "
<< player_specific_property 2 << "...";
return os;
}
This is not how overloading operator<< for ostream works. The left-hand operator is an ostream (hence you gotta overload it as a free function) and the right-hand operator is your object (which is why the virtual mechanism wouldn't easily work.
I suppose you could try:
class Base
{
//...
virtual std::ostream& output(std::ostream&) const;
};
std::ostream& operator<< (std::ostream& os, const Base& obj)
{
return obj.output(os);
}
Now a derived class naturally might call the output method of its parent(s):
class Derived: public Base
//...
virtual std::ostream& output(std::ostream& os) const
{
Base::output(os);
return os << my_specific_data;
}
};
Related
Main question:
In python, we can define things like __unicode__ or __str__ in a class, that way when we call print() or str() on a class (i.e. str(myclass)), we get a customized and readable string representation. In C++, how can this be done for a class? Such that when we call string(myclass) we get a string representation of myclass?
Backstory:
This will probably be tagged as a low quality question, as I am very new to C++.
I'm currently working through the C++ exercises in exercism.io, where the point is to write code to enable the provided test cases to pass. I have already finished 30 of the 39 available exercises, however I am currently stuck on this particular test case code:
const auto actual = string(date_independent::clock::at(t.hour, t.minute));
In the previous exercises, I understood this as "create a namespace named date_independent, have a class in it with the name clock, and make the class have a public function named at, that will accept two parameters(in this case 2 integers hour and minute)". I made the function a static function because the test code does not really instantiate a clock object. I also made the return value to be of type std::string. It worked well for the first few test cases. Unfortunately, I then encountered this test code:
const auto actual = string(date_independent::clock::at(a.hour, a.minute).plus(a.add));
In this instance, my previous solution of returning a string backfired since now I need to call a plus() function on the return value of at(). This obviously cannot be done since at() returns a std::string, and strings don't have member functions. This was then I noticed that there's a string() function (?) encapsulating the entire date_independent::clock::at(a.hour, a.minute).plus(a.add). I'm not sure however where this string() function is coming from, and how I could find out. For python, I would assume that this is some sort of type casting into string, or some other function named string. However, this is C++, and I haven't encountered typecasting done like this yet, so maybe it isn't that. My other idea is that, similar to python, maybe classes can override how standard global functions work with them. Like say when __unicode__ or __str__ is defined in a python class so that print statements can return customized values.
So my question once again is, is my assumption that this string function is supposed to be a member function that is meant to be overridden correct? And if it is, how can it be done in C++? I would appreciate any responses. I'm fairly certain that I'm not seeing something fundamental, since I'm new to the language.
Some of the context of the test code is found below.
...
BOOST_AUTO_TEST_CASE(time_tests)
{
for (timeTest t : timeCases) {
const auto actual = string(date_independent::clock::at(t.hour, t.minute));
BOOST_REQUIRE_MESSAGE(t.expected == actual, errorMsg(t.expected, actual, t.msg));
}
}
...
BOOST_AUTO_TEST_CASE(add_tests)
{
for (addTest a : addCases) {
const auto actual = string(date_independent::clock::at(a.hour, a.minute).plus(a.add));
BOOST_REQUIRE_MESSAGE(a.expected == actual, errorMsg(a.expected, actual, a.msg));
}
}
...
If want to output your class in console or write it to a file, you have to override the << operator for your class.
std::ostream& operator<<(std::ostream& os, const person& person)
{
return os << person.first_name << " " << person.last_name;
}
If you just want a std::string, just add a to_string method that returns the string reprentation of your class.
class person
{
public:
std::string to_string() const
{
return first_name + " " + last_name;
}
private:
std::string first_name;
std::string last_name;
};
Suppose I have a
struct foo { int bar; double baz; };
And a struct foo s; somewhere. I would like to be able to write magic(s) and get a string, or text printed to cout, which includes not just the values of s.bar and s.baz, but also the identifiers 'bar' and 'baz'.
I know C++ doesn't have proper reflection, but maybe something RTTIish (I'm not well-versed in RTTI)? Or perhaps with some minor decoration of the class declaration?
Note: Of course I'm asking about a solution which would work for any type, or at least any struct; obviously I can implement an operator<< for foo's.
We may well have to wait until C++ get reflection facilities added to the language.
This is being actively worked on, by WG21 SG7. What's that? WG21 is the working group of the International Standards Organization (ISO) which develops the C++ language standards. SG7 is the sub-group in charge of exploring the possibilities reflection.
SG7 has a Google Group in which it discusses its ongoing work.
You could implement:
inline std::ostream& operator<<(
std::ostream& os, // stream object
const foo& f
)
{
os << /*ToDo - nice formatting of data members*/
return os;
}
Then this will work with cout etc:
foo f; cout << "My foo is " << f << ".";
This question already has answers here:
How to define a static operator<<?
(4 answers)
Closed 9 years ago.
Let's say I have a class called "Logger". The name is self explanatory, it logs stuff. I have a static method, which logs stuff (Logger::log(string msg)).
I wanted to overload the operator <<, so that I could do something like:
Logger << "AW YEAH, I LOVE C++";
I tried to do this, but couldn't. What I managed, was this:
Logger l;
l << ":(";
...
is it possible what I want to do? And if yes, how?
Thank You in advance :)
If Logger is the name of a class then of course you can't do that. Use something like
Logger &log() {
static Logger l;
return l;
}
log() << "And the answer is" << 42;
Assuming you want to leverage the output operators provide by std::ostream you should not try to overload the output operator! Instead, you'd create a suitable stream buffer (i.e., a class derived from std::streambuf) and implement your custom output logic in that class's overflow() and sync() methods. Your logger would then derive from std::ostream and initialize its base class to use your custom stream buffer.
Overloaded operators operate on values, not on types.
Maybe you should rename your class, and then create a suitable global object. For example:
logger.h:
class mylogger { /* ... */ };
extern mylogger logger;
logger.cpp:
#include "logger.h"
mylogger logger;
Usage:
#include "logger.h"
logger << "Done";
Beware of global initialization issues; though; check out your implementation of std::cout for a way to solve this (e.g. with a Schwartz counter).
It is possible, but you need to figure out what interface you really want. One option is to make your Logger be an std::ostream (inheritance) and then things would kind of work out of the box. The alternative is to maintain a logger that is unrelated (no inheritance) to std::ostream, but then you need to provide Logger& operator<<(Logger&,T const &) for any and all types T you want to log. For the particular case of std::string you could do:
Logger& operator<<(Logger& logger, std::string const& msg) {
logger.log(msg); // need not be, and problably should be static
return logger;
}
Making this generic involves as with most generic code in C++ the use of templates:
template <typename T>
Logger& operator<<(Logger& logger, T const & obj) {
// do specific work based on the type, or a completely generic approach:
std::ostringstream st;
st << obj;
logger.log(st.str());
return logger;
}
At this point you might want to consider adding support for manipulators and... well, if you start down this path, it might make more sense not to create the std::ostringstream in each function, but create a single one as a member, then dump all data into that stream and use some manipulator to extract the string and write it (for example on std::flush or std::ends...)
template <typename T>
Logger& operator<<(Logger& logger, T const& obj) {
logger.stream << obj;
return logger;
}
Logger& operator<<(Logger& logger, std::ostream& (*manip)(std::ostream&)) {
logger.stream << manip;
if (manip == static_cast<std::ostream& (*)(std::ostream&)>(std::flush)) {
logger.write(); // flush to disk
}
return logger;
}
// add support for other manipulators...
Then again you might start wondering if it would not be easier to pull some off the shelf logging library and just use it.
I'd like to create a C++ ostream object that only outputs anything if a condition holds true, to use for debugging. What would be the easiest way to do this? I know that boost has classes that make this easy, but I'd like to know if there's a simple way to do it without boost. The documentation makes it seem like subclassing ostream::sentry would make this possible, but I can't find any source saying that's something that you can/should do.
Don't subclass, it's easier to use a wrapper:
class MaybeOstream
{
public:
MaybeOstream(std::ostream& stream_) : stream(stream_), bOutput(true) {}
void enable(bool bEnable) { bOutput = bEnable; }
template<typename T>
MaybeOstream& operator<< (T x)
{
if(bOutput)
stream << x;
return *this;
}
// Add other wrappers around ostream: operator void*, good(), fail(),
// eof(), etc., which just call through to the ostream
private:
std::ostream& stream;
bool bOutput;
}
Take a look at this paper on filtered streambufs.
I have created a class that allows the user to input their mailing address, order date, type of cookie ordered and the quantity. There were other errors, but I stayed late and with the assistance of my prof, I have fixed them. Now all that is left is that I need to be able to change code to overload the I/O stream operators so that the objects may be used in standard input and output statements.
I'm not sure what all part of the code everyone will need to see, but I'm going to post the parts I believe are needed for what I'm trying to do.
I need to have it where in the output(), I have cout << order << endl; I will look over the net and will hopefully have it ready by tonight. Thanks for everyone's input.
Was instructed to take down my code due to other students from class copying my code pieces to do their work (knew it was possible but didn't think about it)
However, my code is complete.
Implement two functions:
basic_ostream & operator<< (basic_ostream& ostr, const CookieOrder& co)
basic_istream & operator>> (basic_istream& istr, CookieOrder& co)
the operator<<= function will be called when you use cout << order << endl; and the operator>> function will be called when you use the >> (stream extraction) operator. Be very careful how you implement the stream extraction operator.
You may want to declare either of these as friend to the CookieOrder, as that will allow the function to access the private parts of the class as if the function is a member of the class.
edit to respond to changes in the question
delcare your class as before:
class CookieOrder {
public:
// public methods as before
private:
// private parts as before
};
basic_ostream & operator<< (basic_ostream& ostr, const CookieOrder& co);
basic_istream & operator>> (basic_istream& istr, CookieOrder& co);
Implement the two functions using only the public interface of the CookieOrder class.
For example:
basic_ostream & operator<< (basic_ostream& ostr, const CookieOrder& co)
{
ostr << co.get_customerName() << endl;
/* the rest of the output */
}
These functions are not members of the CookieOrder class, they are normal functions with no special access to the CookieOrder class or instanaces of the class.
As far as comparison is concerned, you'd be better off comparing all upper or all lower (rather than each word's first letter upper), it's simpler to set things that way.
Moreover you should get into the habit of putting braces around code
Why do you have a magic number of 6 in your loop? Especially when you only have five (5) elements.
Perhaps the loop should be
...
int loop_size = sizeof(flavors)/sizeof(flavors[0]);
for (int i = 0; i < loop_size; ++i)
{
if (flavors[i] == cookieOrdered)
{
valid_option = true;
break;
}
}
Hint: lookup Case insensitive string comparison in C++