I have an interface that boils down to
class interface
{
protected:
virtual void write(std::string const &) = 0;
};
And derived classes like
class derived : public interface
{
protected:
void write(std::string const & buf)
{
std::cout << buf << std::endl;
}
};
In my application, these objects are passed around as smart pointers, i.e. std::shared_ptr<derived>. I hoped I could overload the << operator, but only for smart pointer of derivatives of my interface. I tried this:
class interface
{
/* ... */
private:
template <typename Derived> friend typename std::enable_if<
std::is_base_of<interface, Derived>::value,
std::shared_ptr<Derived>
>::type & operator<<(std::shared_ptr<Derived> & lhs,
std::string const & rhs)
{
lhs->write(rhs);
return lhs;
}
};
But when I try std::shared_ptr<derived> sp; sp << "test";, the compiler complains that virtual void derived::write(const string&) is protected within this context (this context is my friend function).
Is there a way to achieve this without redundantly writing a stream operator for every derived class?
Why not simply define your operator as:
friend std::shared_ptr<interface> &operator<<(std::shared_ptr<interface> & lhs, std::string const & rhs);
and pass your objects as std::shared_ptr<interface>?
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'm trying to create the following flow:
Having a 'Base' class, with no params or functionality, just so i can hold
Base pointers in a method.
Its derived class, is a template, which implements operator() on given template argument object type.
I'm trying, by using a pointer to base class, call the derived class operator(), in run-time.
I've tried implementing it using CRTP
(https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
But that doesn't seem to work the-other-way-around - when the derived class is a class template.
Here is my code:
class Base {};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const {
return (m_db.*m_func)(obj);
}
}
Now, usage is in another class template, that contains vector of Base class pointers, as follows, and have its own operator() :
template<typename Obj_Type2> /* Upon usage, Obj_Type2 is the same as Obj_Type, this is just to differ the two in the code here */
class BlaBla {
private:
std::vector<const Base *> m_vec;
public:
/* relevant constructors ... */
inline bool operator()(const Obj_Type2 &obj) const {
for(std::vector<const Base *>::const_iterator it = m_vec.begin(); it != m_vec.end(); ++it) {
/*** This is the problematic line V ***/
if( (*it).operator()(obj) ) { /* DO SOMETHING */ }
}
}
Of course the compiler is complaining that there is no matching function to call for in the problematic line that is marked in the code below, but i can't figure out a way to do the relevant call.
1st Solution that came to mind, is to create a virtual operator()(...), with a specific object type e.g. virtual operator()(const uint32_t &obj) in Base class, which works, but my intention is that operator()(...) will receive a variety of object types, and stating a virtual method for each of them is not elegant and seems to break all the template concept i want to implement here.
2nd Solution that came to mind, is somehow passing Ref_Obj and Obj_Type typenames to Base class, to be used in sort of interface method, that will use static_cast to call the appropriate Derived operator (As in CRTP) - But that doesn't seem to work because Derived class is a class template, and also BlaBla class doesn't directly know Ref_Obj typename.
Is there any other way to make the appropriate call to Deriver operator()
There is no clear clean way to do this. The fundamental problem is that there is no such thing as a virtual template method.
The cleanest way I can think of doing this that implements complete type erasure is with a dynamic cast, and a virtual method:
class Base {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Base& obj) const override {
const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj);
if (!derived_obj)
{
throw; // Or maybe return false, or something...
}
return (m_db.*m_func)(*derived_obj);
}
};
Obj_Type must also be derived from Base. This gets the job done at runtime, but there is no compile-time type-checking.
The other approach is to bite the bullet, and forego 100% type erasure:
template<typename Obj_Type>
class Base {
public:
virtual bool operator()(const Obj_Type &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base<Obj_Type> {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const override {
return (m_db.*m_func)(obj);
}
};
So, you can still abstract away operator() on some object to its pure interface, and define the details in the subclass.
Or, another alternative would be a combination of the two:
class SuperBase {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Obj_Type>
class Base : public SuperBase {
public:
virtual bool operator()(const Obj_Type &) const=0;
bool operator()(const Base &obj) const override
{
// Do the dynamic cast check, and forward it to the other
// operator().
}
};
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);
}
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.
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;
}