tags:

views:

123

answers:

3

Say I wanted to have one variable in a class always be in some relation to another without changing the "linked" variable explicitly.

For example: int foo is always 10 less than int bar.

Making it so that if I changed bar, foo would be changed as well. Is there a way to do this? (Integer overflow isn't really possible so don't worry about it.)

Example: (Obviously doesn't work, but general code for an understanding)

class A
{
    int x;
    int y = x - 10; // Whenever x is changed, y will become 10 less than x
};
+8  A: 

No, you can't do that. Your best option for doing this is to use accessor and mutator member functions:

int getFoo()
{
    return foo_;
}

void setFoo(int newFoo)
{
    foo_ = newFoo;
}

int getBar()
{
    return foo_ + 10;
}

void setBar(int newBar)
{
    foo_ = newBar - 10;
}
James McNellis
I don't want to do it explicitly.
trikker
That's the only way to do it...
EToreo
Okay well thanks for the response. I guess I'll figure something out.
trikker
You don't have to figure it out... James just showed you how.
Barry Wark
There are other tricks, especially if one wants to be able to have a reference / pointer to the 'shadow' value, in which case a temporary does not work. But we agree it won't be automatic.
Matthieu M.
@Barry Wark. You have no idea what my project is, so you have no idea what the implementation is like and how everything is set up. I ended up not using this method because the "linked" variable is only needed in 1 or 2 places so providing accessors and mutators would be extreme overengineering.
trikker
Extreme overengineering, really? The runtime overhead of an inline function like the ones shown is practically zero.
Jeremy Friesner
There are other ways to accomplish what I was trying to solve that are simpler and clearer than what was stated above. Plus, they don't lower encapsulation. I'm not saying that James McNellis's idea was bad, it just didn't suit what I was trying to do.
trikker
+3  A: 

This is called an invariant. It is a relationship that shall hold, but cannot be enforced by the means provided by the programming language. Invariants should only be introduced when they are really necessary. In a way the are a relatively "bad" thing, since they are something that can be inadvertently broken. So, the first question you have to ask yourself is whether you really have to introduce that invariant. Maybe you can do without two variables in this case, and can just generate the second value from the first variable on the fly, just like James suggested in his answer.

But if you really need two variables (and very often there's no way around it), you'll end up with an invariant. Of course, it is possible to manually implement something in C++ that would effectively link the variables together and change one when the other changes, but most of the time it is not worth the effort. The best thing you can do, if you really need two variables, again, is to be careful to keep the required relationship manually and use lots of assertions that would verify the invariant whenever it can break (and sometimes even when it can't), like

assert(y == x - 10);

in your case.

Also, I'd expect some advanced third-party C++ libraries (like, Boost, for example) to provide some high level assertion tools that can be custom-programmed to watch over invariants in the code (I can't suggest any though), i.e. you can make the language work for you here, but it has to be a library solution. The core language won't help you here.

AndreyT
+1 But I think you should add something about classes and private members to your answer. Access control helps enforcing invariants.
sellibitze
+2  A: 

You could create a new structure which contains both variables and overload the operators you wish to use. Similar to James McNellis' answer above, but allowing you to have it "automatically" happen whenever you operate on the variable in question.

class DualStateDouble 
{
public:
  DualStateDouble(double &pv1,double &pv2) : m_pv1(pv1),m_pv2(pv2)
  // overload all operators needed to maintain the relationship
  // operations on this double automatically effect both values
private:
  double *m_pv1;
  double *m_pv2;
};
Mark Essel