Overloaded output operator in base class - c++

I have a number of classes that represent various computer components, each of which have an overloaded << operator declared as follows:
friend ostream& operator << (ostream& os, const MotherBoard& mb);
Each returns an ostream object with a unique stream describing that component, some of which are composed of other components. I decided to create a base class called Component in order to generate a unique id as well as some other functions that all the components will publicly derive. Of course, the overloaded << operator doesn't work with pointers to Component objects.
I was wondering how I would effect something like a pure virtual function that will be overwritten by each derived class's << operator so I could do something like:
Component* mobo = new MotherBoard();
cout << *mobo << endl;
delete mobo;
Also related to: overloading << operators and inherited classes

Maybe something like this:
#include <iostream>
class Component
{
public:
// Constructor, destructor and other stuff
virtual std::ostream &output(std::ostream &os) const
{ os << "Generic component\n"; return os; }
};
class MotherBoard : public Component
{
public:
// Constructor, destructor and other stuff
virtual std::ostream &output(std::ostream &os) const
{ os << "Motherboard\n"; return os; }
};
std::ostream &operator<<(std::ostream &os, const Component &component)
{
return component.output(os);
}
int main()
{
MotherBoard mb;
Component &component = mb;
std::cout << component;
}

Related

Why does the `operator<<` not work on member pointing to derived type? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have a class Base with a member pointing to a derived type Derv:
class Derv;
class Base
{
protected:
std::vector<std::shared_ptr<Derv>> opnds;
...
}
The derived class looks like this:
#include "Base.h"
class Derv:
public Base
{
...
}
Now I want to cout all Base and derived types by serializing the items from opnds. I read that something like the following is the standard approach for that (since I might want to override the serialization from other derived classes). I included into Base.h:
friend std::ostream &operator<<(std::ostream &os, math_struct const &m);
virtual void serialize(std::ostream& os) const;
In Base.cpp I implemented:
#include <string>
void Base::serialize(std::ostream& os) const
{
for (std::size_t i = 0; i < this->opnds.size(); ++i) {
os << ", " << *this->opnds[i]; // Error: no operator "<<" matches these operands
}
}
std::ostream& operator<<(std::ostream &os, math_struct const &m) {
m.serialize(os);
return os;
}
But the recursive application of << in Base::serialize serialize doesn't work. It seems to have to do with the derived class being referenced in the base class member. An earlier version where I head std::vector<std::shared_ptr<Base>> opnds worked fine.
I'm new to C++, so probably I got something basic wrong...
Please check if you have defined Derv before defining serialize because otherwise the compiler cannot know, that Derv can be cast to Base.
The following should do:
#include <iostream>
#include <memory>
#include <vector>
class Base;
class Derv;
std::ostream& operator << (std::ostream& out, const Base&);
class Base
{
public:
void serialize(std::ostream& os) const;
protected:
std::vector<std::shared_ptr<Derv>> opnds;
};
// class Derv must be _defined_ before defining the functon Base::serialize!
class Derv : public Base { };
void Base::serialize(std::ostream& os) const
{
for (std::size_t i = 0; i < this->opnds.size(); ++i) {
os << ", " << *this->opnds[i];
}
}
std::ostream& operator << (std::ostream& out, const Base&)
{
out << "operator called" << std::endl;
return out;
}

Array of pointers to the base class that contains objects of derived classes and overloaded << operator

I have the following problem.
I've created an array of pointers to objects from the base class, but I'm storing in this array also the pointers to the objects from the derived classes.
I also overloaded the <<operator in each class to display the objects.
However, when I apply this overloaded <<operator to the above mentioned array, it treats all the pointers as if there were pointing to the objects of the base class.
Below I present the code that depicts the problem.
I need this overloaded operator to work correctly because I need to save the objects pointed by the array in the file.
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
class Base
{
public:
int basevar;
Base(): basevar(1) {};
virtual void dosth(){};
friend ostream & operator<<(ostream & screen, const Base & obj);
};
ostream & operator<<(ostream & screen, const Base & obj)
{
screen << obj.basevar;
return screen;
};
class Der1: public Base
{
public:
int de1;
Der1(): de1(2) {};
virtual void dosth()
{
cout << "Der1" << endl;
}
friend ostream & operator<<(ostream & screen, const Der1 & obj);
};
ostream & operator<<(ostream & screen, const Der1 & obj)
{
Base b;
b = static_cast <Base>(obj);
screen << b;
screen << " " << obj.de1;
return screen;
};
class Der2: public Base
{
public:
int de2;
Der2(): de2(3) {};
virtual void dosth()
{
cout << "Der2" << endl;
}
friend ostream & operator<<(ostream & screen, const Der2 & obj);
};
ostream & operator<<(ostream & screen, const Der2 & obj)
{
Base b;
b = static_cast <Base>(obj);
screen << b;
screen << " " << obj.de2;
return screen;
}
int main()
{
Base * array[] = {new Base(), new Der1(), new Der2()};
for(int i=0; i<3; ++i)
{
cout << *array[i]; // <- always displays objects as if they were from the base class
}
return 0;
}
You can declare a virtual function in the base class the following way
class Base
{
public:
int basevar;
Base(): basevar(1) {};
virtual std::ostream & out( std::ostream &os ) const
{
return os << basevar;
}
virtual void dosth(){};
friend ostream & operator<<(ostream & screen, const Base & obj);
};
In this case the operator will look like
ostream & operator<<(ostream & screen, const Base & obj)
{
return obj.out( screen );
};
and in derived classes redefine the virtual function. For example
class Der1: public Base
{
public:
int de1;
Der1(): de1(2) {};
std::ostream & out( std::ostream &os ) const
{
return Base::out( os ) << " " << obj.de1;
}
virtual void dosth()
{
cout << "Der1" << endl;
}
};
In this case there is no need to define the operator for derived classes.

How to overload operator << for derived classes using a shared base class?

I'm trying to overload operator<< in several subclasses.
I have a superclass called Question, which has an enumerated value type, and a string question.
The subclasses of this class are TextQuestion, ChoiceQuestion, BoolQuestion and ScaleQuestion. TextQuestion has no additional data fields. ChoiceQuestion has a vector of strings, to store the multiple choice possibilities. BoolQuestion has no additional data fields. ScaleQuestion has two int-values, low_ and high_, for the scale.
class Question {
public:
enum Type{TEXT, CHOICE, BOOL, SCALE};
Question():
type_(), question_() {}
Question(Type type, std::string question):
type_(type), question_(question) {}
friend std::ostream& operator<<(std::ostream& out, const Question& q);
virtual void print(std::ostream& out) const;
virtual ~Question();
private:
Type type_;
std::string question_;
};
class TextQuestion: public Question {
public:
TextQuestion():
Question() {}
TextQuestion(Type type, std::string question):
Question(type, question) {}
void print(std::ostream& out) const;
virtual ~TextQuestion();
};
class ChoiceQuestion: public Question {
public:
ChoiceQuestion():
Question(), choices_() {}
ChoiceQuestion(Type type, std::string question, std::vector<std::string> choices):
Question(type, question), choices_(choices) {}
void print(std::ostream& out) const;
virtual ~ChoiceQuestion();
private:
std::vector<std::string> choices_;
};
class BoolQuestion: public Question {
public:
BoolQuestion():
Question() {}
BoolQuestion(Type type, std::string question):
Question(type, question) {}
void print(std::ostream& out) const;
virtual ~BoolQuestion();
};
class ScaleQuestion: public Question {
public:
ScaleQuestion():
Question(), low_(), high_() {}
ScaleQuestion(Type type, std::string question, int low = 0, int high = 0):
Question(type, question), low_(low), high_(high) {}
void print(std::ostream& out) const;
virtual ~ScaleQuestion();
private:
int low_, high_;
};
Now, I'm trying to overload operator<< for all these subclasses and I tried using this example
So I made a virtual print function in the superclass, overloaded the print function in each subclass and the operator<< in the superclass calls the print-function.
std::ostream& operator<<(std::ostream& out, const Question& q) {
q.print(out);
return out;
}
void Question::print(std::ostream& out) const {
std::string type;
switch(type_) {
case Question::TEXT:
type = "TEXT";
break;
case Question::CHOICE:
type = "CHOICE";
break;
case Question::BOOL:
type = "BOOL";
break;
case Question::SCALE:
type = "SCALE";
break;
}
out << type << " " << question_;
}
void TextQuestion::print(std::ostream& out) const {
Question::print(out);
}
void ChoiceQuestion::print(std::ostream& out) const {
Question::print(out);
out << std::endl;
int size(get_choices_size());
for (int i = 0; i < size; ++i) {
out << choices_[i] << std::endl;
}
}
void BoolQuestion::print(std::ostream& out) const {
Question::print(out);
}
void ScaleQuestion::print(std::ostream& out) const {
Question::print(out);
out << " " << low_ << " " << high_;
}
I did it exactly like in the example, but when I output my Questions, it always uses the baseclass and outputs only the type and the question. The compiler never uses the subclasses.
Only virtual functions allow for dispatch according to the dynamic type of an object (given the static type of a base class).
Only nonstatic member functions can be virtual.
operator << cannot be virtual because it cannot be a nonstatic member function, because its first argument must be the stream.
You can call a virtual function from an operator << which accepts a reference to the base class.
Calling a virtual function from a non-virtual function, to preserve interface aspects which are not overridden, is called the non-virtual idiom.
Ah, I did not see any virtual upon first read but now I do. If you are not getting subclass behavior where expected, a likely culprit is slicing, where you create an object of base class type and assign it a value from a subclass object.
TextQuestion q( "What is hello, world?" ); // Original object
Question & qr( q ); // Reference, not another object
Question q2( q ); // Base class object with copied subset (slice) of data.
std::cout << q << '\n'; // Observe subclass behavior.
std::cout << qr << '\n'; // Observe subclass behavior due to dynamic typing.
std::cout << q2 << '\n'; // Observe superclass behavior due to slicing.
You cannot override operator<< in your classes because it cannot be a member (you cannot pass this as the right operand).
Instead, have a virtual print function overriden in each subclass, and define global/nanespace scope operator<< in terms of it.

Qt serialization, nonmember QDataStream & operator<<

I have a class IDocument which serve as a interface for some classes. It has some abstracts methods (virtual ... = 0).
I would like to do such all subclasses also have to implement an operator for serialization:
In addition to the overloaded stream operators documented here, any Qt classes that you might want to serialize to a QDataStream will have appropriate stream operators declared as non-member of the class:
I'm not even sure how I would make an abstract operator, but how do I define it nonmember?
A non-member operator is a free function, pretty much like any other free function. For QDataStream, on operator<< would look like:
QDataStream& operator<<(QDataStream& ds, SomeType const& obj)
{
// do stuff to write obj to the stream
return ds;
}
In your case, you could implement your serialization like this (this is just one way of doing it, there are others):
#include <QtCore>
class Base {
public:
Base() {};
virtual ~Base() {};
public:
// This must be overriden by descendants to do
// the actual serialization I/O
virtual void serialize(QDataStream&) const = 0;
};
class Derived: public Base {
QString member;
public:
Derived(QString const& str): member(str) {};
public:
// Do all the necessary serialization for Derived in here
void serialize(QDataStream& ds) const {
ds << member;
}
};
// This is the non-member operator<< function, valid for Base
// and its derived types, that takes advantage of the virtual
// serialize function.
QDataStream& operator<<(QDataStream& ds, Base const& b)
{
b.serialize(ds);
return ds;
}
int main()
{
Derived d("hello");
QFile file("file.out");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << d;
return 0;
}

Making operator<< virtual?

I need to use a virtual << operator. However, when I try to write:
virtual friend ostream & operator<<(ostream& os,const Advertising& add);
I get the compiler error
Error 1 error C2575: 'operator <<' :
only member functions and bases can be
virtual
How can I turn this operator virtual?
The problem with this setup is that the operator<< you defined above is a free function, which can't be virtual (it has no receiver object). In order to make the function virtual, it must be defined as a member of some class, which is problematic here because if you define operator<< as a member of a class then the operands will be in the wrong order:
class MyClass {
public:
virtual ostream& operator<< (ostream& out) const;
};
means that
MyClass myObject;
cout << myObject;
will not compile, but
MyClass myObject;
myObject << cout;
will be legal.
To fix this, you can apply the Fundamental Theorem of Software Engineering - any problem can be solved by adding another layer of indirection. Rather than making operator<< virtual, consider adding a new virtual function to the class that looks like this:
class MyClass {
public:
virtual void print(ostream& where) const;
};
Then, define operator<< as
ostream& operator<< (ostream& out, const MyClass& mc) {
mc.print(out);
return out;
}
This way, the operator<< free function has the right parameter order, but the behavior of operator<< can be customized in subclasses.
You define your operator << to call a virtual print method:
class Base
{
protected:
virtual void print(std::ostream& str) const = 0;
public:
friend std::ostream& operator<<(std::ostream& str, Base const& data)
{
data.print(str);
return str;
}
}
It looks like you really want to provide output functionality for a hierarchy of classes, and if so, you can provide a friend operator << that calls a virtual function.
class Parent
{
public:
friend std::ostream& operator<< (std::ostream& os, const Parent& p);
// ... other class stuff
protected:
virtual void printMyself(std::ostream& os) const
{
// do something if you must, or make this a pure virtual
}
};
std::ostream& operator<< (std::ostream& os, const Parent& p)
{
p.printMyself(os);
return os;
}
class Child : public Parent
{
// other class stuff...
protected:
virtual void printMyself(std::ostream os) const
{
// whatever you need to do
}
};
Also detailed in the C++ FAQ