Passing a collection of partially editable objects to an algorithm

95 Views Asked by At

I simplified my problem with a simple example : immagine I manage a collection of elements std::vector<Element>, each element having several members :

struct Element
{
  public:
    double foo;
    double bar;
};

Then, I want to define an abstract class BarEvaluator, for algorithms computing the values of b from the values of a. My first idea is the following :

class BarEvaluator
{
  public:
    virtual void evaluate(std::vector<Element>& elements) const = 0;
};

From that, I can implement several algorithms, for example, an algorithme computing the bar values as the square of the foo values :

class SqrBarEvaluator
{
  public:
    virtual void evaluate(std::vector<Element>& elements) const
    {
      for(unsigned long int i = 0; i < elements.size(); ++i)
        elements[i].bar = elements[i].foo * elements[i].foo;
    }
};

This is working well. But I think it's not a really good architecture, because my algorithm is also able to modify the foo values. I don't want that.

Then I would like to be able to give my collection to the algorithm with a kind of "filter" allowing to modify only the bar variable and not the foo variable in each element. Is it possible with C++98 ? I have no idea how to do that.

Remark 1 : I don't want to do that with public or private in Element. You can immagine I also want to create algorithms FooEvaluator computing foo values from bar values, with writing access to foo and not to bar.

Remark 2 : The algorithm can require all the collection to compute each value.

2

There are 2 best solutions below

0
On

You can use a wrapper:

class BarElementWrapper
{
public:
    BarElementWrapper(Element& e) : elem(e) { }
    double getFoo() { return elem.foo; }
    void setBar(double b) { elem.bar = b; }

private:
    Element& elem;
}

And then your algorithm receives a collection of BarElementWrapper.

4
On

Maybe you should pull the loop out of the interface.

class BarEvaluator
{
  public:
    virtual double evaluate(const Element& element) const = 0;
};

class SqrBarEvaluator
{
  public:
    virtual double evaluate(const Element& element) const
    {
      return element.foo * element.foo;
    }
};

Then you call it like this:

std::vector<Element> elements;
...
for (std::vector<Element>::iterator it = elements.begin(); it != elements.end(); ++it) {
    it->bar = barEvaluator.evaluate(*it);
}