Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - Function calling when changing member value

My goal is to fire a event receiver when a value is changed in a class. My solution to this is using get and set functions. However, I do not want any performance problems when reading the values. In the class below:

class Vertex {
 public:
  const double& GetX() { return _x; } // should inline automatically
  const double& GetY() { return _y; } // ' '                     ' '
  void SetX(const double& x); // complex stuff in source file
  void SetY(const double& y); // ' '                      ' '
 private:
  double _x, _y;
}

I put the definition of the getters in the header files, because this should allow them to be inlined.

My question is: is there any way to automatically call a function when a value is changed that does not require me to include function definitions in the header file? Or is there perhaps a visibility level that allows anyone to read the data, but only the class itself to modify it? Or maybe something else?

I know an alternative approach would be manually calling an update function, but that looks ugly:

vertex.X = 5;
vertex.Update();

Thank you in advance.

Edit:

So far I've heard some great answers. The solution depends on your goal:

  • Easy: getters and setters; not very clean though.
  • Clean: property class (or proxy); implementing operators is not as easy though.

However, what about efficiency?

I just worked out a nice trick for the separate read/write-access permissions I speculated about earlier:

class Vertex {
 public:
  Vertex(double x, double y)
      : _x(x), _y(y), X(_x), Y(_y) { } // defined here for readability
  void SetX(double x) { _x = x; update(); } // defined here for readability
  void SetY(double y) { _y = y; update(); } // update would be the callback
  const double& X, Y;
 private:
  double _x, _y;
}
like image 788
RPFeltz Avatar asked Dec 28 '22 06:12

RPFeltz


1 Answers

If all you're looking for is clean, then probably the cleanest way to do this would be to have a "property" object, like in C#:

template<typename T>
class Property {
public:
    Property(std::function<void(T)> callback) : data(), callback(callback) { }

    Property& operator=(const T& newvalue) {
        data = newvalue;
        callback(data);

        return *this;
    }

    operator T() const {
        return data;
    }

private:
    T data;
    std::function<void(T)> callback;
};

class Vertex {
public:
    Vertex() : X(&xcallback), Y(&ycallback) { }

    Property<double> X, Y;
};

(The functions are inline for conciseness on SO, you can move them out if you want.) Then you can do

Vertex v;

v.X = 4;
v.Y = 2.3443;

And every time the value is assigned to, the respective callback will be called. And you can use v.X and v.Y in place of wherever you'd use a double as well so they behave like normal doubles (except for the fact that you'd have to implement -=, +=, etc).

like image 199
Seth Carnegie Avatar answered Jan 12 '23 14:01

Seth Carnegie