1

Say I have:

struct foo{

int bar;
int baz;
...
bool flag;
}

Can an access operator -> or . be overridden to detect if bar or any other member variable is modified ?

EDIT:

The purpose is if I have many member variables and any of them is changed, I have a quick way of setting a flag, instead of using setters to encapsulate all the variables, making the code verbose.

Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190
  • thats what encapuslation is for. You can make `bar` private. Actually there has been proposals for overloading the dot operator, but the one I know wouldnt do what you want, because `f.bar` would still only access `bar` https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf – 463035818_is_not_an_ai Jan 10 '23 at 09:05
  • is `private` not an option? If not then I would go for some `ModificationTracked bar;` member, which encapsulates the modification tracking – 463035818_is_not_an_ai Jan 10 '23 at 09:07
  • 1
    your edit doesnt make the motivation much more clear. If you have many members and you want to easily check if something changed you use `operator==` – 463035818_is_not_an_ai Jan 10 '23 at 09:08
  • 1
    I don't think it is possible as `foo f;` will have members with indeterminate values and reading which will lead to undefined behavior. – Jason Jan 10 '23 at 09:20
  • 2
    For the question as asked: no. In an expression like `a->b`, overloads of `operator->()` return either another object that has an overloaded `operator->()` (which will be called recursively) or a pointer which is dereferenced to access a member (or call a member function). So the access of the member occurs after `operator->()` returns. `.` is one of the operators that cannot be overloaded. Instead, declare the member `private` and implement (public) setters and getter functions as the only means for code outside the class to access those members. – Peter Jan 10 '23 at 09:55
  • 1
    You can overload `->` (it's tricky, but there are probably duplicates here on how to do it). Overloading `.` is not possible in any current C++ standard (including C++23), although (unless I dreamt this) I think Stroustrup is on the case. – Bathsheba Jan 10 '23 at 10:24
  • Here's one: https://stackoverflow.com/questions/8777845/overloading-member-access-operators – Bathsheba Jan 10 '23 at 10:25
  • 2
    @Bathsheba your werent dreaming. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf Not sure if there is something more recent on the subject. And note that this proposal would not help OP, because if I understand correctly `f.bar` would still just access the member `bar` – 463035818_is_not_an_ai Jan 10 '23 at 10:30
  • @Peter thanks. I considered getters and setters, and alternatively storing all the variables in a map, but both would become unwieldy from a maintenance purpose, hence was looking for either a hacky solution or some kind of design pattern I was not aware of to reduce the amount of code I had to maintain / write. Would have been cool if there was some way to do it. I wonder if there is some way to accomplish this overriding the assignment operator...maybe I should just bite the bullet and write out all the code...thanks to all for all the suggestions. – Rahul Iyer Jan 11 '23 at 02:54
  • No it is not possible – n. m. could be an AI Jan 11 '23 at 06:16

2 Answers2

1

Your approach is flawed because even if you override access operators you will not catch pointers writing the actual memory.

If most of the variables have the same type you can use an enum for flags and a single function to set or get a specific variable.

For example:

private:
  int bar;
  int baz;

public:
  enum IntVariables { varBar, varBaz };
  bool flag;

  void setVariable(int varId, int value) {
    flag = true;
    if (varId == varBar)
      bar = value;
    else if (varId == varBaz)
      baz = value;
  }
Cosmin
  • 21,216
  • 5
  • 45
  • 60
  • Thank you, I considered a similar approach using a map to store the variables, but the con is that you will need an solution for each variable type, and when updating the class you would have to ensure that care is taken to include new additions as well. Hence I was somehow trying to figure out a hack to "detect" changes and react... :) – Rahul Iyer Jan 11 '23 at 02:51
0

I considered the following approach:

Just use a wrapper class that can have any data type, but implement all operations. In this same wrapper class override operators, and use the wrapper class in other class that require any modifications of member variables to be detected.

template <class T>
class wrapper {
  private:
    T var;
    ... .. ...
  public:
    T doSomethingToVar(T arg);
    ... .. ...
    //Wherever the variable is modified send out a notification to whomever needs to detect the changes.
};

Pros:

  • When declaring variables in whichever class needs to detect modification of variables, it is easy to declare using the wrapper, without much additional code.
  • To ensure modifications are detected, need to implement functions / getters / setters / overload operators to detect modifications. This is tricky, and requires some thought.

Cons:

  • Tricky to implement a general purpose wrapper that can detect all modifications, since complex types can have functions that modify themselves in ways one is not aware of.

Notes: How to ensure that every method of a class calls some other method first?

This answer is a work in progress, and I think it may be useful to others and maybe just cool to know about eventually, so open to comments. Will keep updating.

Update:

While writing out the above answer, I considered a different approach, of shifting responsibility onto the member variable classes:

class DetectChanges{

void onDetectChanges(){ //This function should be called by all implementing classes when the class has changes. }

Can make it a design choice that all member variables inherit from DetectChanges.

The above two approaches are what I'm considering now. Not a solution yet, but thought I would put it out for comments and see if eventually we can figure something out. }

Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190