Search code examples
c++cgal

Derived class calls parent's method


(Note: The corresponding gist is available here.)


I have a number of methods which are derived from std::unary_function<K::Point_3, K::FT> plus typedef K::Point_3 Point; (the underlying library CGAL requires it) – The class is called Function.

I now need to add a number of instances of derived classes (example: MySphere) to a Function_vector:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Implicit_to_labeling_function_wrapper.h>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;

class Function: public std::unary_function<K::Point_3, K::FT>
{
public:
  typedef K::Point_3 Point; // necessary
  // I'd rather not define operator() here
  virtual K::FT operator()(K::Point_3 p) const {return 0.0;}
};

class MySphere: public Function
{
public:
  virtual K::FT operator()(K::Point_3 p) const {return 3.14;}
};

typedef CGAL::Implicit_multi_domain_to_labeling_function_wrapper<Function>
                                               Function_wrapper;
typedef Function_wrapper::Function_vector Function_vector;

int main()
{
  MySphere f1;

  Function_vector v;
  v.push_back(f1);

  std::cout << f1(CGAL::ORIGIN) << std::endl; // MySphere::operator()
  std::cout << v[0](CGAL::ORIGIN) << std::endl; // Function::operator() :(

  return 0;
}

Problem:

Function_vector does not accept pointers, so the actually abstract Function class cannot be virtual and needs to implement operator() from std::unary_function. When adding a MySphere instance to the Function_vector, MySphere gets cast into Function and Function's operator() is called, not MySphere's.

How to have v[0] call MySphere::operator()?


Solution

  • As a workaround, one can create another wrapper MyFun and feed it into Function à la

    #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
    #include <CGAL/Implicit_to_labeling_function_wrapper.h>
    
    #include <memory>
    
    typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
    typedef K::FT FT;
    
    class MyFun: public std::unary_function<K::Point_3, K::FT>
    {
      public:
      virtual K::FT operator()(K::Point_3 p) const = 0;
    };
    
    class MySphere: public MyFun
    {
    public:
      virtual K::FT operator()(K::Point_3 p) const {return 3.14;}
    };
    
    class Function: public std::unary_function<K::Point_3, K::FT>
    {
      public:
      typedef K::Point_3 Point;
    
      explicit Function(std::shared_ptr<MyFun> fun):
        fun_(fun)
      {
      }
    
      virtual K::FT operator()(K::Point_3 p) const {
        return fun_->operator()(p);
      }
    
      private:
      std::shared_ptr<MyFun> fun_;
    };
    
    
    typedef CGAL::Implicit_multi_domain_to_labeling_function_wrapper<Function> Function_wrapper;
    typedef Function_wrapper::Function_vector Function_vector;
    
    int main()
    {
      auto f1 = std::make_shared<MySphere>();
    
      Function_vector v;
      v.push_back(Function(f1));
    
      std::cout << (*f1)(CGAL::ORIGIN) << std::endl;
      std::cout << v[0](CGAL::ORIGIN) << std::endl;
    
      return 0;
    }