In C++ is there a way to use the insertion operator for a class method?
This operator<< overload is working:
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
Complex() {};
~Complex() {};
};
I can do this:
int main()
{
Complex* o = new Complex();
std::cout << "This is test: " << *o << "." << std::endl; // => This is test: test overload.
}
I know about stream manipulators, like this:
std::ostream& welcome(std::ostream& out)
{
int data = 1;
out << "WELCOME " << data << "\r\n";
return out;
}
int main()
{
std::cout << "Hello " << welcome; // => "Hello WELCOME 1\r\n"
}
How can I put the welcome method into the Complex class and then how shall I call it from cout (please note that welcome method must access some class member variables)?
My trial:
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
std::ostream& welcome(std::ostream& out) {
out << "WELCOME " << data << "\r\n";
return out;
}
Complex() { data = 1; };
~Complex() {};
private:
int data;
};
int main()
{
Complex* o = new Complex();
std::cout << "This is test2: " << o->welcome << std::endl; // compile error
}
One easy way to pick a different << overload is to use a different type.
#include <iostream>
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
struct extra_info {
const Complex& parent;
extra_info(const Complex& p) : parent(p) {}
friend std::ostream& operator<<(std::ostream& out, const extra_info& ei){
int i = 1;
out << "extrainfo " << i;
return out;
}
};
extra_info extrainfo() {
return {*this};
}
Complex() {};
~Complex() {};
};
int main() {
Complex c;
std::cout << c << "\n";
std::cout << c.extrainfo();
}
Output:
test overload
extrainfo 1
I suppose in your real code you are using members. Hence the helper type must hold a reference to the Complex instance.
Related
I was trying to learn operator overloading in C++ PL. I made an exercise shown below. What I want to do is overload << operator for each derived class and use it on my main. But whenever I do it, its only working for Base class. What is the problem here?
Class Employee:
class Employee {
public:
string name;
int id;
int exp_level;
double salary;
Employee() {
this->name = "";
this->id = 0;
this->exp_level = 0;
this->salary = 0.0;
}
~Employee() {
//WTF
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Employee& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << endl;
return os;
}
};
Class Technical:
class Technical : public Employee {
public:
string profession;
Technical() {
this->profession = "";
}
~Technical() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Technical& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Technical" << endl;
return os;
}
};
Class Engineer:
class Engineer : public Employee {
public:
Engineer() {
}
~Engineer() {
}
virtual void calculateSalary() {
//CODE
}
virtual void registerX() {
//CODE
}
friend ostream& operator<<(ostream& os, const Engineer& e) {
os << e.name << " " << e.exp_level << " " << e.id << " " << e.salary << "Engineer" << endl;
return os;
}
};
Main Method:
int main()
{
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
cout << *e << endl;
cout << *t << endl;
cout << *ee << endl;
}
Output:
0 0 0
0 0 0
0 0 0
C++ chooses the best overload based on the static type's of the function arguments, and because the type is Employee in this case, the Employee's operator<< gets called.
If you want it to call the correct version when you have a static type pointer / reference to it that doesn't match it's dynamic type you'll have to use a virtual function or use dynamic_casts / typeid to check for the concrete runtime type (virtual functions are the cleanest approach imho)
Example: godbolt
class Employee {
public:
virtual ~Employee() = default;
friend std::ostream& operator<<(std::ostream& os, const Employee& e) {
return e.put(os);
}
protected:
virtual std::ostream& put(std::ostream& os) const {
os << "Employee!";
return os;
}
};
class Technical : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Technical Employee!";
return os;
}
};
class Engineer : public Employee {
protected:
std::ostream& put(std::ostream& os) const override {
os << "Engineer Employee!";
return os;
}
};
int main() {
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
std::cout << *e << std::endl;
std::cout << *t << std::endl;
std::cout << *ee << std::endl;
delete ee;
delete t;
delete e;
}
would result in:
Employee!
Technical Employee!
Engineer Employee!
Also keep in mind that once you have at least 1 virtual function in a class then the destructor should almost definitely be also virtual.
e.g.:
Employee* e = new Technical();
delete e;
would only call ~Employee(), but not ~Technical(), if the destructor is not virtual.
So whenever you want to delete an object through a pointer to one of it's base-classes the destructor needs to be virtual, otherwise it's undefined behavior.
Due to these declarations
Employee* e = new Employee();
Employee* t = new Technical();
Employee* ee = new Engineer();
the static type of the expressions *e, *t, *ee is Employee &. So the operator
friend ostream& operator<<(ostream& os, const Employee& e)
is called for all three objects.
A simple way to make the friend operator << "virtual" is to define in each class a virtual function like for example
virtual std::ostream & out( std::ostream & ) const;
and define the (only) friend operator like
friend ostream& operator<<(ostream& os, const Employee& e)
{
return e.out( os );
}
The virtual function out need to be redefined in each derived class.
This question already has answers here:
C++ Overloading operator << for child classes
(2 answers)
Closed 2 years ago.
I have 3 classes, and I'd like each one to print out differently to the terminal, I have a node class that represents a vertex in a BDD graph, right now I'm trying to write code to do logical operations on the nodes.
The Node class is setup as such:
class Node {
char name;
public:
Node() { name = '0'; }
Node(char c) { name = c; }
Node(const Node& n) { name = n.name; }
friend ostream& operator<<(ostream& stream, const Node& n);
};
ostream& operator<<(ostream& stream, const Node& n) {
return stream << "{ Node " << n.name << " }";
}
The operator classes are setup as such:
class Operation {
public:
Node result;
friend std::ostream& operator<<(std::ostream& stream, const Operation& op);
Operation() {}
Operation(const Operation& op) { cout << "Copying " << *this << endl; }
virtual ~Operation() { cout << "Destroying " << *this << endl; }
virtual Node compute() {
cout << "Computing " << *this << endl;
result = Node('1');
return result;
}
};
std::ostream& operator<<(std::ostream& stream, const Operation& op) {
return stream << "Operation { Unspecified }";
}
class UnaryOperation : public Operation {
public:
Node arg1;
UnaryOperation(const Node& arg1) { this->arg1 = arg1; }
UnaryOperation(const UnaryOperation& op) : Operation::Operation(op) {
arg1 = op.arg1;
}
virtual ~UnaryOperation() {}
friend ostream& operator<<(ostream& stream, const UnaryOperation& op);
};
ostream& operator<<(ostream& stream, const UnaryOperation& op) {
return stream << "Operation { arg1: " << op.arg1 << " }";
}
class BinaryOperation : public UnaryOperation {
public:
Node arg2;
BinaryOperation(const Node& arg1, const Node& arg2) : UnaryOperation(arg1) {
this->arg2 = arg2;
}
BinaryOperation(const BinaryOperation& op) : UnaryOperation::UnaryOperation(op) {
arg2 = op.arg2;
}
virtual ~BinaryOperation() {}
friend ostream& operator<<(ostream& stream, const BinaryOperation& op);
};
ostream& operator<<(ostream& stream, const BinaryOperation& op) {
return stream << "Operation { arg1: " << op.arg1 << ", arg2: " << op.arg2;
}
For debugging reasons, these messages need to print out as such, but when I run this
Node apply(Operation& op) {
cout << "Performing apply operation on " << op << endl;
op.compute();
return op.result;
}
int main() {
Node a('a'), b('b');
UnaryOperation uop(a);
BinaryOperation bop(a, b);
cout << uop << endl;
cout << bop << endl;
apply(uop);
apply(bop);
}
I get
Operation { arg1: { Node a } }
Operation { arg1: { Node a }, arg2: { Node b }
Performing apply operation on Operation { Unspecified }
Computing Operation { Unspecified }
Performing apply operation on Operation { Unspecified }
Computing Operation { Unspecified }
Destroying Operation { Unspecified }
Destroying Operation { Unspecified }
Needless to say, this is not very helpful for debugging.
Why is it doing this, and how do I fix it?
The friend function is not virtual. It is selected according to the type of the second argument.
In this function
Node apply(Operation& op) {
cout << "Performing apply operation on " << op << endl;
op.compute();
return op.result;
}
the type of the argument is Operation &. So in this statement
cout << "Performing apply operation on " << op << endl;
there is called the friend function for an object of the type Operation &.
You could make the friend function "virtual" the following way as it is shown in the demonstrative program below.
#include <iostream>
class Operation
{
public:
virtual ~Operation() = default;
private:
virtual std::ostream & out( std::ostream &os = std::cout ) const
{
return os << "This is an Operation";
}
friend std::ostream& operator <<( std::ostream &stream, const Operation &op )
{
return op.out( stream );
}
};
class UnaryOperation : public Operation
{
std::ostream & out( std::ostream &os = std::cout ) const override
{
return os << "This is an Unary Operation";
}
friend std::ostream& operator <<( std::ostream &stream, const UnaryOperation &op )
{
return op.out( stream );
}
};
class BinaryOperation : public UnaryOperation
{
std::ostream & out( std::ostream &os = std::cout ) const override
{
return os << "This is a Binary Operation";
}
friend std::ostream& operator <<( std::ostream& stream, const BinaryOperation &op )
{
return op.out( stream );
}
};
void f( const Operation &op )
{
std::cout << op << '\n';
}
int main()
{
BinaryOperation bop;
f( bop );
return 0;
}
Its output is
This is a Binary Operation
I just want to print the two values of my structure, but can't compile my code - I get: no operator “<<” matches these operands.
#include <iostream>
using namespace std;
struct SCoor
{
int i, j;
bool operator == (const SCoor & tmp) const
{
return (i == tmp.i && j == tmp.j);
}
bool operator < (const SCoor & tmp) const
{
return (i < tmp.i || (i == tmp.i && j < tmp.j));
}
ostream& operator << (ostream &o) {
return o << i << " " << j;
}
};
int main()
{
SCoor tmp = { 3, 3 };
cout << tmp;
return 0;
}
How do I have to overload the operator "<<"?
You overload the << operator as a member function if you want your structure to be on the left hand side of the expression. So:
struct SCoor
{
// ...
SCoor& operator << (Stuff const& s) {
// ...
return *this;
}
};
// ...
Stuff stuff;
SCoor scoor;
scoor << s; // insert s into my SCoor
If you want to make your struct the right hand side of the << expression you have to define a standalone function:
std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
However it is quite common to make the external function a friend function and to define it in the struct definition:
struct SCoor
{
// ...
friend std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
};
// ...
SCoor scoor;
std::cout << scoor << '\n';
But it is not a member of your struct, it is just defined inside its definition for convenience.
I want to add indent during serialization of object. But since operator<< can only contains 2 parameters:
struct A {
int member;
};
ostream& operator<<(ostream& str, const A& a)
{
return str;
}
Now my solution is like this:
struct A {
int m1;
int m2;
};
void print(const A& a, const int indent)
{
cout << string(indent, '\t') << m1 << endl;
cout << string(indent + 1, '\t') << m2 << endl;
}
Is there any better method of adding extra parameters during object serialization?
You could make a tuple or pair and send it to a operator<<function
or you could also do something like
std::ostream& operator<<(std::ostream& os, const A& param)
{
auto width = os.width();
auto fill = os.fill();
os << std::setfill(fill) << std::right;
os << std::setw(width) << param.m1 << std::endl;
os << std::setw(width) << fill << param.m2 << std::endl;
return os;
}
int main()
{
struct A a{1,2};
std::cout.width(4);
std::cout.fill('\t');
std::cout << a << std::endl;
}
As you can see, only the overloaded version of the stream insertion operator for the base class is called on both instances. I understand why it's so. It's because there is no dynamic binding. But, how do I fix it?
#include <iostream>
using namespace std;
class A {
int i;
char c;
public:
A(int i = 0, char c = ' ') {
this->i = i;
this->c = c;
}
int getI() { return i; }
char getC() { return c; }
friend ostream& operator << (ostream&, A&);
};
class B : public A {
double d;
public:
B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
friend ostream& operator << (ostream&, B&);
};
ostream& operator << (ostream& out, A& a) {
out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
return out;
}
ostream& operator << (ostream& out, B& b) {
out << "\nInteger: " << b.getI() << "\nCharacter: " << b.getC() << "\nDouble: " << b.d << endl;
return out;
}
int main() {
A* a = new A (10, 'x');
B* b = new B(20, 'y', 5.23);
A* array[] = { a, b };
cout << *(array[0]);
cout << "\n______________________________\n";
cout << *(array[1]);
delete a;
delete b;
cin.get();
return 0;
}
How can I make cout << *(array[1]); call the overloaded stream insertion operator that takes an object of B as one of it's arguments?
You can't make it call the overloaded operator, since overloading is resolved at compile time.
To do resolution at runtime, i.e. use dynamic dispatch, you need to move the code that does the printing to a virtual member function.
Then call that from the operator (you only need one, for the base class).
class A
{
public:
// ...
// Override this in B
virtual void print(std::ostream& o) const
{
o << "\nInteger: " << i << "\nCharacter: " << c << endl;
}
// ...
};
ostream& operator << (std::ostream& out, const A& a) {
a.print(out);
return out;
}