vendredi 4 mars 2016

"Dynamic" type of argument without template or downcast (?)

I have my fancyFunction which takes a set of elements implementing interface A. The function does a complicated analysis of those elements, based on properties read through interface A. During this analysis, it will call methods of a Consumer c which will take the elements as arguments.

The Consumer is designed to take arguments of a specific type which has absolutely nothing to do with A.

You could imagine that A is an abstraction for edges in a graph. The graph is analyzed in fancyFunction and - for example - every time the function "crosses" an edge, it will send that edge to a Consumer which prints additional information stored in the edge that has nothing to do with it being an edge.

The code given below would of course not compile in a typed language (particularly C++), but leaving out the types (Matlab, Python), the code would work.

To make it work in a typed language (particularly C++), I see two options:

  1. Declare the function as

    template <class CONSUMER> void fancyFunction(A[] setOfAs, CONSUMER c){ ... }

  2. Declare operation1 and operation2 to take the most general object and then do a downcast in the implementation.

What do you recommend to do in that situation? (As far as I see, the visitor pattern is NOT an option.)

Full code outline (I did not use C++ in a while, so please excuse if there are minor syntactical mistakes.):

void fancyFunction(A[] setOfAs, Consumer* c){
  // do fancy analysis of setOfAs by properties
  // read through interface A

  double x = setOfAs[i]->getX();

  // call functions in c with arguments of setOfAs[j]
  ...
  c->operationX(setOfAs[i]);
  ...
  c->operationY(setOfAs[j]);
  ...
}

class A{
  virtual double getX();
}

class Consumer{
  virtual void operationX(??? x); // whoops, what type do we expect?
  virtual void operationY(??? y); // whoops, what type do we expect?
}

class Consumer1{
  void operationX(Obj1 x){ ... } // whoops, override with different type
  void operationY(Obj1 y){ ... } // whoops, override with different type 
}

class Consumer2{
  void operationX(Obj2 x){ ... } // whoops, override with different type
  void operationY(Obj2 y){ ... } // whoops, override with different type
}

class Obj1 : public A {};
class Obj2 : public A {};

void test(){

    Obj1 o1[];
    Obj2 o2[];

    Callback1 c1;
    Callback2 c2;

    fancyFunction(o1, &c1);
    fancyFunction(o2, &c2);
}

Aucun commentaire:

Enregistrer un commentaire