This question already has answers here:
Templates and overloadering operator << [duplicate]
(5 answers)
Closed 7 years ago.
I'm trying to implement a sort of virtual operator << that lets me send a IBase class object to cout so that it calls the Derived class' operator <<. Is this possible?
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
template <typename U>
friend std::ostream& operator<<(std::ostream& os, const Derived<U>& dt);
private:
T data_;
};
template <typename T>
Derived<T>::Derived(T data)
: IBase(),
data_(data)
{
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt)
{
os << dt.data_;
return os;
}
int _tmain(int argc, _TCHAR* argv[])
{
IBase* base = new Derived<int>(5);
std::cout << *base;
}
The << operator is a function, not a method and thus it can not be virtual. However you can still achieve what you want- remember that the operator<< takes a reference as parameter? Well polymorphism works on those too. Simply add another virtual method that you call from the << operator.
Have a look at this short example I put together:
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
virtual string toString() const {
return "base";
}
};
class Child : public Base {
public:
virtual string toString() const {
return "child";
}
friend ostream& operator<<(ostream& out, const Base& b);
};
ostream& operator<<(ostream& out, const Base& b) {
out << b.toString();
return out;
}
int main() {
Child c;
cout << c;
return 0;
}
And here is a link in ideone: http://ideone.com/EmP1oP
Your goal can't be attained through templates alone as dereferencing a IBase* gets you a IBase& - template instantiation occurs at compile time and the compiler has no access to the runtime type.
(Dynamic dispatch only happens when you invoke a member function of an object, and a binary operator can't be a member of its right-hand operand.)
So your templated operator will never be used if you pass a dereferenced IBase* to operator <<.
Instead, add a virtual output function to the base and override it:
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
virtual std::ostream& output(std::ostream&) const = 0;
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
virtual std::ostream& output(std::ostream& os) const
{
os << data;
return os;
}
private:
T data_;
};
std::ostream& operator<<(std::ostream& os, const IBase& dt)
{
return dt.output(os);
}
You can make it virtual for real with a help of simple template rig (which, in addition, does not prevent de-virtualization).
struct X {
virtual std::ostream& repr(std::ostream& out) const;
}
template <class X>
std::enable_if_t<
std::is_same<
std::void_t<
decltype(std::declval<X>().repr(std::declval<std::ostream>()))>,
void>::value,
std::ostream&>
operator<<(X const& x)
{
return x.repr(out);
}
Related
I have a base class called ISignalFilter and I want to create derived classes such that all the derived classes can use an operator overload * to combine into another derived class called ProductFilter.
The problem is, product filter stores the base class and calls the base class method filtered_value. I want the ProductClass to call the derived class method filtered_value. How would I do this?
#include <iostream>
using namespace std;
template <typename T>
class ISignalFilter;
template <typename F>
class ProductFilter;
template <typename T>
class ISignalFilter {
public:
virtual T filtered_value(const T& value) {
(void)value;
std::cout<<"Error this should not be called."<<std::endl;
// BOOST_LOG_TRIVIAL(error) << "Base case usage of method not allowed";
std::abort();
};
virtual ProductFilter<T> operator*(ISignalFilter<T>& other) {
return ProductFilter<T>(*this, other);
}
};
template <typename F>
class ProductFilter : public ISignalFilter<F> {
public:
ProductFilter(const ISignalFilter<F>& a, const ISignalFilter<F>& b) {
a_ = a;
b_ = b;
}
F filtered_value(const F& value) override {
return b_.filtered_value(a_.filtered_value(value));
}
ISignalFilter<F> a_;
ISignalFilter<F> b_;
};
template <typename T>
class IdentityFilter : public ISignalFilter<T> {
public:
IdentityFilter() {}
T filtered_value(const T& value) override { return value; }
};
int main() {
auto filter1 = IdentityFilter<int>();
auto filter2 = filter1 * filter1;
std::cout<<filter2.filtered_value(1)<<std::endl; //should output one.
return 0;
}
Let's play with non-template classes to resolve your title question.
My suggestion is to use different named methods:
class Base
{
public:
bool operator==(const Base& other) const
{
return equal_to(other);
}
protected:
virtual bool equal_to(const Base& other) const = 0;
};
In the above code fragment, the operator== is redirected to call a method, equal_to which is tagged so that child classes must implement it.
Whether derived classes use the operator== or call equal_to is up to the coder.
Note: for best results, overloading operator== should be in each derived class. See also "object slicing".
the main problem, as #user253751 said in comment, is you need to store reference/pointer for dynamic polymorphism to work.
there are some other thing to change
mark the method const (or accept non-const for ProductFilter constructor)
the operator can be defined outside of ISignalFilter, and as it's actually a functionality of ProductFilter, it's reasonable to do it.
use pure virtual function (=0) to catch error at compile time (and your code actually would shows error because you cannot create instance of ISignalFilter<T>)
you probably also want to return const T& for filtered_value
the final code
template <typename T>
struct ISignalFilter {
virtual T filtered_value(const T& value) const = 0;
};
template <typename T>
struct ProductFilter : ISignalFilter<T> {
ProductFilter(const ISignalFilter<T>& a, const ISignalFilter<T>& b)
:a(a),b(b){}
T filtered_value(const T& value) const override {
return b.filtered_value(a.filtered_value(value));
}
const ISignalFilter<T> &a, &b;
};
template<typename T>
ProductFilter<T> operator*(const ISignalFilter<T>& a, const ISignalFilter<T>& b) {
return ProductFilter<T>(a,b);
}
https://godbolt.org/z/oxxKx9z4z
I want to create a overloaded operator<< for a template base class, that calls the toString function for the child class. The issue is that the toString function of the child class is constexpr, which mean I cannot make it a virtual function of the base class. Here is what I want to do:
template<typename T>
class Base {
public:
Base(const T& t) : m_val(t) {}
friend std::ostream & operator<<(std::ostream &os, const Base& base);
protected:
const T m_val;
};
class Child1 : public Base<SomeLiteralType1> {
public:
using Base::Base;
constexpr const char* toString() {
const char* LUT[] = {"aa", "bb"};
return LUT[m_val]; // <-- assume T can be converted to int
}
};
class Child2 : public Base<SomeLiteralType2> {
...
};
std::ostream & operator<<(std::ostream &os, const Base& base) {
// cannot access toString() since it is not defined in Base
// maybe using dynamic_cast?
}
int main() {
Child1 c1 = {...};
Child2 c2 = {...};
// I want to be able to use << directly:
std::cout<<c1<<std::endl;
std::cout<<c2<<std::endl;
}
Use CRTP to get access to the derived class:
template <typename T, typename Derived>
class Base {
...
friend std::ostream& operator<<(std::ostream& os, const Base& base) {
return os << static_cast<const Derived&>(base).toString();
}
...
};
class Child1 : public Base<int, Child1> {
...
};
Compiler Explorer
Since c++20, virtual function can be constexpr, so you can have:
template<typename T>
class Base {
public:
constexpr Base(const T& t) : m_val(t) {}
virtual const char* toString() = 0;
friend std::ostream & operator<<(std::ostream &os, const Base& base)
{
return os << base.toString();
}
protected:
const T m_val;
};
class Child1 : public Base<SomeLiteralType1> {
public:
using Base::Base;
constexpr const char* toString() override {
const char* LUT[] = {"aa", "bb"};
return LUT[m_val]; // <-- assume T can be converted to int
}
};
In previous version, as you don't need constexpr in the base class anyway, you might have a virtual function and the constexpr function:
template<typename T>
class Base {
public:
constexpr Base(const T& t) : m_val(t) {}
virtual const char* virtualToString() = 0;
friend std::ostream & operator<<(std::ostream &os, const Base& base)
{
return os << base.virtualToString();
}
protected:
const T m_val;
};
class Child1 : public Base<SomeLiteralType1> {
public:
using Base::Base;
constexpr const char* toString() {
const char* LUT[] = {"aa", "bb"};
return LUT[m_val]; // <-- assume T can be converted to int
}
const char* virtualToString() override {
return toString();
}
};
Suppose we have this scenario(maybe a little bit artificial)
class OStream
{
virtual void f1() = 0;
...
virtual void f10() = 0;
template<typename T>
OStream& operator<<(const T& t)
{
//doing something
}
};
class MyClass : public OStream
{
virtual void f1() override;
...
virtual void f10() override;
}
In another CPP file, there is another Foo class defined with a friend function like this
friend OStream& operator<<(OStream& ostream, Foo& obj)
{
//doing something with obj
}
Now consider a completely different file that contains such a snippet
...
MyClass obj; //suppose the constructor is defined
Foo foo; //there as well
obj << foo; // which operator is called???? I guess the second one
...
And what operator will be called if I overload OStream::operator<< inside MyClass(it is templated(thus non-virtual), thus I am just hiding the original one?
I have a basic abstract class Base.
class Base
{
protected:
string m_Name;
public:
virtual string Name() { return m_Name; }
virtual string Type() = 0;
virtual bool isEqual(Base* rhs) = 0 ;
//virtual ostream& operator<< (ostream& out) const;
};
I would like to overload the operator << to display objects that inherit from Base.
I cannot use a void print() function because these objects that inherit from Base also have some objects that can only be displayed by operator <<.
How can I overload the operator << ?
A common pattern is to provide a virtual print method, and use that in an ostream&<< operator:
class Base
{
public:
void print(std::ostream& o) const { /* do your stuff */ }
virtual ~Base() {}
};
std::ostream& operator<<(std::ostream& o, const Base& b)
{
b.print(o);
return o;
}
The idea is that each derived type implements print(ostream&) according to its needs.
Is this the only way of overloading the ostream& operator<< for a derived class without duplicating code for the base class? Are the casts not something to be avoided?
I don't see any other way, except to define some kind of function in the base class that will represent the data of the base class as something that std::operator<< could "eat up" (like a string?), doing the same thing for the derived class (calling the base class stream representation function within the derived class stream. rep. function of course).
What is the ideal solution to this problem?
#include <iostream>
class Base
{
private:
int b_;
public:
Base()
:
b_()
{};
Base (int b)
:
b_(b)
{};
friend std::ostream& operator<<(std::ostream& os, const Base& b);
};
std::ostream& operator<< (std::ostream& os, const Base& b)
{
os << b.b_;
return os;
}
class Derived
:
public Base
{
private:
int d_;
public:
Derived()
:
d_()
{};
Derived (int b, int d)
:
Base(b),
d_(d)
{};
friend std::ostream& operator<<(std::ostream& os, const Derived& b);
};
std::ostream& operator<< (std::ostream& os, const Derived& b)
{
os << static_cast<const Base&>(b) << " " << b.d_;
return os;
}
using namespace std;
int main(int argc, const char *argv[])
{
Base b(4);
cout << b << endl;
Derived d(4,5);
cout << d << endl;
return 0;
}
Well ... casting should be avoided if done in contexts where the result is not correctly defined, but casting into a base is always safe.
It is possible to avoid the explicit cast by considering that a derived reference decays into the base reference, so you can use an implicit conversion, like in this case:
std::ostream& operator<< (std::ostream& os, const Derived& b)
{
const Base& bs = b;
os << bs << " " << b.d_;
return os;
}
static_cast<const Base&>(b)
is safe and there is nothing incorrect, because every derived class object is also an Base class object and can be treated like one.
Casts are dangerous only when used in a reckless way, You must use casts where they are needed and in a correct manner, that is the very purpose of their provision by the language standard.
If you don't like the casts, you can have your operator call a writeTo function that is implemented using the template method pattern.
e.g.
class Base {
public:
std::ostream& writeTo(std::ostream& ostr) const { os << b_; return this->doWriteTo(os); }
private:
int b_;
virtual std::ostream& doWriteTo(std::ostream& ostr) const = 0; // pure virtual
};
class Derived {
private:
int d_;
virtual std::ostream& doWriteTo(std::ostream& ostr) const {return ostr << d_;}
};
std::ostream& operator<<(std::ostream& ostr, const Derived& d) {
return d.writeTo(ostr);
}
Actually, using this pattern, you can write operator<< once and for all for Base:
std::ostream& operator<<(std::ostream& ostr, const Base& b) {
return b.writeTo(ostr);
}
This pattern also elminates the need to make operator<< a friend.
You could change things around like this:
struct Base {
int b_;
void print(ostream &o) { o << b_; }
};
struct Derived : Base {
int d_;
void print(ostream &o) {
Base::print(o);
o << ' ' << d_;
}
};
ostream &operator<<(ostream &o, Base &b) {
b.print(o);
return o;
}
ostream &operator<<(ostream &o, Derived &d) {
d.print(o);
return o;
}
If Base had virtual functions (which in this example it doesn't), then print could be one of them, and you could get rid of the multiple overloads of operator<<.