I have a class that is derived from ostream:
class my_ostream: public std::ostream
{
// ...
}
I want to make a manipulator (for example do_something), that works specifically to this class, like this:
my_ostream s;
s << "some text" << do_something << "some more text";
I did the following:
std::ostream &do_something(std::ostream &os)
{
my_ostream *s = dynamic_cast<my_ostream*>(&os);
if (s != NULL)
{
// do something
}
return os;
}
This works, but is rather ugly. I tried the following:
my_ostream &do_something(my_ostream &s)
{
// do something
return s;
}
This doesn't work. I also tried another approach:
class my_ostream: public std::ostream
{
// ...
my_ostream &operator<<(const do_something & x)
{
// do something
return *this;
}
}
This still doesn't work.
You need to add support for manipulators in your class:
#include<iostream>
class my_ostream : public std::ostream
{
public:
std::string prefix;
my_ostream():prefix("*"){}
// manipulator support here:
my_ostream& operator<<( my_ostream&(*f)(my_ostream&)){
f(*this);
return *this;
}
};
my_ostream& operator<<(my_ostream &st, const std::string &s){
std::cout << st.prefix << s;
return st;
}
// manipulator: clear prefix
my_ostream& noprefix(my_ostream &st){
st.prefix="";
}
int main(){
my_ostream s;
std::string str1("text");
std::string str2("text");
s << str1 << noprefix << str2;
}
Related
I have a class named Demo and in that class I have overloaded the Text() method for setting and getting it's private variable called text.
#ifndef DEMO_H
#define DEMO_H
#include <string>
#include <iostream>
using namespace std;
class Demo {
string text;
public:
Demo() {};
Demo(string newText) : text(newText) {};
void Text(string updatedText);
string Text();
};
#endif // !DEMO_H
void Demo::Text(string updatedText) {
text = updatedText;
}
string Demo::Text() {
return text;
}
Then in another class, I have used the method in following way-
#include "Demo.h"
int main()
{
Demo d;
d.Text("test");
cout << d.Text() << endl;
return 0;
}
This works fine. However, I want to set the parameter of the method with "=" operator. So rather than
d.Text("test");
I want to do
d.Text = "test";
Is it possible to achieve in C++ and if so then how. I was thinking of operator overloading but I couldn't achieve the goal. Can anyone please suggest.
The closest you can get in c++ to express property like getter / setter functions similar as in c# is to provide class member functions like these:
class Demo {
string text;
public:
void Text(const string& updatedText) { text = updatedText; }
const string& Text() const { return text; }
};
That idiom is used a lot in the c++ standard library like here.
I want to do
d.Text = "test";
What you can do is
class Demo {
public:
string& Text() { return text; }
};
and
d.Text() = "test";
but that totally defeats the concept of encapsulation of data.
The right way to proceed is overloading the assignment '=' operator and use as below.
class Demo {
string text;
public:
Demo() {};
Demo(string newText) : text(newText) {};
**void operator =(const string& val) { text = val; }**
void Text(string updatedText);
string Text();
};
int main()
{
Demo d;
//d.Text("test");
d = "hello world";
cout << d.Text() << endl;
return 0;
}
You could define your Text property as an object T. T could then overload some common property operations ( haven't figured out how a common getter call like Object o; o.set(d.Text); would be implemented yet ) :
#include <iostream>
using namespace std;
class T {
string _text;
public:
void operator =(const string& t) { _text = t; }
friend ostream& operator<<(ostream& os, const T& obj)
{
cout << obj._text;
return os;
}
};
class Demo {
public:
T Text;
};
int main()
{
Demo d;
d.Text = "test";
cout << d.Text << endl;
}
I'm debugging a program and I would like to make printing from that pattern:
std::cout << firstVar << ", " << secondVar << ", " << thirdVar << endl ;
shorter, i.e, the same thing should happen if we will write the code:
shortPrint(std::cout) << firstVar << secondVar << thirdVar;
note: there is no limit for the variables quantity, it can be 1 and it can be 20, so that should also work:
shortPrint(std::cout) << firstVar << secondVar << thirdVar << anotherVar << oneMoreVar;
Someone told me that the easiest wat to do that is to create class that is called "shortPrint".
Can anyone help me figuring this out?
For start, I would say that I only need to implement a constructor and operator << overloading, but I'm not sure how to do that exactly in that case.
Yes create a shortPrint class with an appropriate overloaded operator. Something like this :
class shortPrint {
ostream &o;
public:
shortPrint(ostream &o) : o(o) {}
template <typename T> shortPrint &operator<<(const T &t) {
o << t << ',';
return *this;
}
// support for endl, which is not a value but a function (stream->stream)
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
That should work (basically).
To eliminate the problem of extra commas use this :
class shortPrint {
class shortPrint2{
shortPrint &s;
public:
shortPrint2(shortPrint &s) : s(s) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
s.o << ',' << t ;
return *this;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
s.o << pf;
return s;
}
};
ostream &o;
shortPrint2 s2;
public:
shortPrint(ostream &o) : o(o), s2(*this) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
o << t;
return s2;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
You can do something like the following:
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
explicit _ostream_wrap(std::ostream & ost)
:m_ost(ost)
{}
private:
std::ostream& m_ost;
};
template <class OSTREAM>
_ostream_wrap shortPrint(OSTREAM & o)
{
return _ostream_wrap(o);
}
//...
shortPrint(std::cout) << 1 << 2;
however this implementation will not work on rvalues:
//you can't do something like the following:
shortPrint(MyOstream(some_args)) << 1;
This is because the class _ostream_wrap keeps a reference to the stream and for rvalues case it needs to make a copy. To make a copy you need to have two implementations (this would be the final version):
template <class OSTREAM>
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap<OSTREAM>& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
public:
//the constructor is harder to write so i decided
//that for this i will keep the member public
OSTREAM m_ost;
};
template <class OSTREAM>
_ostream_wrap<OSTREAM&> shortPrint(OSTREAM & o)
{
_ostream_wrap<OSTREAM&> rvalue;
rvalue.m_ost = o;
return rvalue;
}
template <class OSTREAM>
_ostream_wrap<OSTREAM> shortPrint(const OSTREAM & o)
{
_ostream_wrap<OSTREAM> rvalue;
rvalue.m_ost = o;
return rvalue;
}
Here's something with very basic functionality:
#include <iostream>
struct shortPrint {
explicit shortPrint(std::ostream& os)
: strm(&os), first(true) {}
template<typename T>
shortPrint& operator<<(T&& t)
{
if (first) {
first = false;
} else {
*strm << ", ";
}
*strm << std::forward<T>(t);
return *this;
}
shortPrint& operator<<( std::ostream& (*func)(std::ostream&) )
{
*strm << func;
return *this;
}
private:
std::ostream* strm;
bool first;
};
int main()
{
int i = 3;
shortPrint(std::cout) << "1" << 2 << i << std::endl;
shortPrint(std::cout) << 4;
}
The tricky part is getting the commas to be printed correctly. I chose to print them before every streamed object, except before the very first one. As you can see, there's one general operator<< template that simply prints the comma and forwards the argument. The next problem are stream manipulators, because we don't want to print commas before them. The other operator<< overload takes care of that. If you want to be more generic, there's two more you need to take care of (see no. 9 here ).
Hope that helps.
Return the ostream from the function. Something like:
std::ostream &shortPrint(std::ostream &out) {
//whatever you need here
return out;
}
Edit: you the kind of formatting you need, you need to make a class with overloaded stream operator that returns the class. But you need to keep the reference to the needed stream in the class.
Is it possible to use operator<< to push strings into a vector. I searched a lot but only find stream examples.
class CStringData
{
vector< string > myData;
// ...
// inline operator << ... ???
};
I want this to use as a simple elipsis (like void AddData(...) ) exchange for
robust parameters.
CStringData abc;
abc << "Hello" << "World";
Is this possible at all ?
You can define operator<< as:
class CStringData
{
vector< string > myData;
public:
CStringData & operator<<(std::string const &s)
{
myData.push_back(s);
return *this;
}
};
Now you can write this:
CStringData abc;
abc << "Hello" << "World"; //both string went to myData!
But instead of making it member function, I would suggest you to make it friend of CStringData:
class CStringData
{
vector< string > myData;
public:
friend CStringData & operator<<(CStringData &wrapper, std::string const &s);
};
//definition!
CStringData & operator<<(CStringData &wrapper, std::string const &s)
{
wrapper.myData.push_back(s);
return wrapper;
}
The usage will be same as before!
To explore why should you prefer making it friend and what are the rules, read this:
When should I prefer non-member non-friend functions to member functions?
You need to use std::vector.push_back() or std::vector.insert() to insert elements inside a vector.
Following piece of code appends to stream. similary you can add it to vector also.
class CustomAddFeature
{
std::ostringstream m_strm;
public:
template <class T>
CustomAddFeature &operator<<(const T &v)
{
m_strm << v;
return *this;
}
};
as it is template so you can use it for other types also.
// C++11
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string>& operator << (vector<string>& op, string s) {
op.push_back(move(s));
return op;
}
int main(int argc, char** argv) {
vector<string> v;
v << "one";
v << "two";
v << "three" << "four";
for (string& s : v) {
cout << s << "\n";
}
}
Here is what I would like to do:
class Msg {
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { }
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text);
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg)in << " Text " << in.text;
}
Unfortunately, this doesn't work as the cast to Msg on the second last line fails as Msg is abstract. I would however like to have the code to output the information for the parent in only one place. What is the correct way to do this? Thanks!
EDIT: Sorry, just to be clear, it is this line return ss << (Msg)in << " Text " << in.text; I don't know how to write.
Try ss<<(Msg const&)in.
And probably you have to make operator a friend of Greeting class.
#include "iostream"
#include "string"
typedef enum { TypeGreeting} MsgType;
class Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Msg const& in);
int target;
public:
Msg(int target): target(target) { }
virtual ~Msg () { };
virtual MsgType GetType()=0;
};
inline std::ostream& operator <<(std::ostream& ss,Msg const& in) {
return ss << "Target " << in.target;
}
class Greeting : public Msg {
friend inline std::ostream& operator <<(std::ostream& ss,Greeting const& in);
std::string text;
public:
Greeting(int target,std::string const& text) : Msg(target),text(text) {};
MsgType GetType() { return TypeGreeting; }
};
inline std::ostream& operator <<(std::ostream& ss,Greeting const& in) {
return ss << (Msg const&)in << " Text " << in.text;
}
int _tmain(int argc, _TCHAR* argv[])
{
Greeting grt(1,"HELLZ");
std::cout << grt << std::endl;
return 0;
}
Not great design, but solves your problem.
I have a C++ class MyObject and I want to be able to feed this data like I would to a osstream (but unlike a direct sstream, have the incoming data be formatted a special way). I can't seem to figure out how to overload a operator for MyObject to eat input given to it.
class MyObject {
public:
ostringstream s;
FEEDME
};
int main() {
MyObject obj;
obj.FEEDME << "Hello" << 12345;
// I want obj.s == ":Hello::12345:"
}
I want it so every item fed in be surrounded by : :
So in the given example, s = ":Hello::12345" should be the final outcome. What my question is, how can I tell the object that when ever a <<something, put : : around the something.
Is this possible?
try this:
class MyObject {
public:
template <class T>
MyObject &operator<<(const T &x) {
s << ':' << x << ':';
return *this;
}
std::string to_string() const { return s.str(); }
private:
std::ostringstream s;
};
MyObject obj;
obj << "Hello" << 12345;
std::cout << obj.to_string() << std::endl;
There are certain things you won't be able to shove into the stream, but it should work for all the basics.
You may find the answers for How do I create my own ostream/streambuf? helpful.
I would take a slightly different approach and create a formater object.
The formater object would then handle the inserting of format character when it is applied to a stream.
#include <iostream>
template<typename T>
class Format
{
public:
Format(T const& d):m_data(d) {}
private:
template<typename Y>
friend std::ostream& operator<<(std::ostream& str,Format<Y> const& data);
T const& m_data;
};
template<typename T>
Format<T> make_Format(T const& data) {return Format<T>(data);}
template<typename T>
std::ostream& operator<<(std::ostream& str,Format<T> const& data)
{
str << ":" << data.m_data << ":";
}
int main()
{
std::cout << make_Format("Hello") << make_Format(123);
}