Home > Net >  How do you create an operator overload on a base class such that all derived classes will use it wit
How do you create an operator overload on a base class such that all derived classes will use it wit

Time:01-14

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 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

  • Related