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;
}
CodePudding user response:
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".
CodePudding user response:
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
forProductFilter
constructor) - the operator can be defined outside of
ISignalFilter
, and as it's actually a functionality ofProductFilter
, 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 ofISignalFilter<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);
}