Emre Sahin
Emre Sahin

Reputation: 467

Abstract Functors in C++

I would like to write an abstract base class

class func_double_double_t : public unary_function<double, double>
{
    virtual double operator()(double x) = 0;
};

and specialize it for several different types

class func_pow_t : public func_double_double_t
{
 public:
    func_pow_t(double exponent) : exponent_(exponent) {};
    virtual double operator()(double x) { return pow(x, exponent_); };
}

class func_exp_t : public func_double_double_t
...

and pass these to a function when necessary:

double make_some_calculation(double num, func_double_double_t f)
{
     return f(x);
}

But I can't define an object of type func_double_double_t because it's abstract. I can pass a pointer to the function, but using f like f->operator()(num) seems against the spirit of operator overloading in the first place. ((*f)(num) is better, but still.)

Is there way to make operator overloading and such abstraction play nicely together?

Upvotes: 3

Views: 1230

Answers (5)

unkulunkulu
unkulunkulu

Reputation: 11912

You can simply pass a reference into your function:

double make_some_calculation(double num, func_double_double_t& f)
{
    return f(x);
}

Upvotes: 3

AnT stands with Russia
AnT stands with Russia

Reputation: 320481

If you are trying to implement it through run-time polymorphism, you need the following

  1. The base class function shall be declared virtual (where is it?)

    class func_double_double_t : public unary_function<double, double>
    {
        virtual double operator()(double x) = 0;
    };
    
  2. The derived classes do not need virtual when inheriting from base class (why did you put it there?)

    class func_pow_t : public func_double_double_t {
      ...
    
  3. The calling function should receive the object by pointer or reference

    double make_some_calculation(double num, func_double_double_t& f)
    {
      return f(x);
    }
    

    or

    double make_some_calculation(double num, func_double_double_t* f)
    {
      return (*f)(x);
    }
    

Upvotes: 0

xtofl
xtofl

Reputation: 41509

Although you can get there by passing the function as a reference, the C++11 standard has these functor types built in:

double make_some_calculation(double d, std::function< double(double) > f) {
   return f(d);
}


...
auto add_2=std::bind( std::plus(), 2.0 );
double result=make_some_calculation(1.1, add_2);

Upvotes: 1

There are a couple of basic concepts that you might want to revisit. First the direct answer to your question is that you should pass a reference, which allows for the nice syntax and passing different derived instances.

Beyond that, if you want runtime polymorphic behavior then your operator() should be virtual in the base class (maybe left out while copying to the question? --i.e. without virtual the pure-specifier =0 is ill formed)

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490128

It seems like the obvious answer would be to pass a reference, so you just use: f(num), about like usual.

Unless you need to be able to use different function objects at run-time (e.g., have an array of functors of different types, and invoke them all in a loop) you might consider making the function to be invoked a template parameter instead:

template <class F>
double do_some_calculation(double num) { 
    return f(num);
}

If the function to be used is known at compile time, this will generally be preferred.

Upvotes: 0

Related Questions