Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Get/Set accessors - how do I avoid typing repetitive code?

Tags:

I'm writing a pretty large library, and I find myself writing almost identical accessors all the time. I already have several dozen accessors such as the one below.

Question: How can I declare/implement accessors to save typing all this repetitive code? (No #defines please; I'm looking for C++ constructs.)

Update: Yes, I do need accessor functions, because I need to take pointers to these accessors for something called Property Descriptors, which enable huge savings in my GUI code (non-library).

.h file

private:
    bool _visible;
public:
    bool GetVisible() const { return _visible; }
    void SetVisible (bool value);

// Repeat for Get/SetFlashing, Get/SetColor, Get/SetLineWidth, etc.

.cpp file

void Element::SetVisible (bool value)
{
    _visible = value;
    this->InvalidateSelf(); // Call method in base class
    // ...
    // A bit more code here, identical in 90% of my setters.
    // ...
}

// Repeat for Get/SetFlashing, Get/SetColor, Get/SetLineWidth, etc.
like image 888
adigostin Avatar asked Nov 29 '15 13:11

adigostin


2 Answers

I find myself writing almost identical accessors all the time. I already have several dozen accessors such as the one below.

This is a sure design smell that you are writing accessors "for the sake of it". Do you really need them all? Do you really need a low-level public "get" and "set" operation for each one? It's unlikely.

After all, if all you're doing is writing a getter and a setter for each private data member, and each one has the same logic, you may as well have just made the data members public.

Rather your class should have meaningful and semantic operations that, in the course of their duties, may or may not make use of private data members. You will find that each of these meaningful operations is quite different from the rest, and so your problem with repetitive code is vanquished.

As n.m. said:

Easy: avoid accessors. Program your classes to do something, rather than have something.

Even for those operations which have nothing more to them, like controlling visibility, you should have a bool isVisible() const, and a void show(), and a void hide(). You'll find that when you start coding like this it will promote a move away from boilerplate "for the sake of it" getters & setters.

like image 95
Lightness Races in Orbit Avatar answered Oct 17 '22 09:10

Lightness Races in Orbit


Whilst I think Lightness Races in Orbit makes a very good point, there is also a few ways that can be used to implement "repeating code", which can be applied, assuming we do indeed have a class that have "many things that are similar that need to be controlled individually, so kind of continuing on this, say we have a couple of methods like this:

void Element::Show()
{
   visible = true;
   Invalidate();
   // More code goes here. 
}

void Element::Hide()
{
   visible = false;
   Invalidate();
   // More code goes here. 
}

Now, to my view, this breaks the DRY (Do not Repeat Yourself) principle, so we should probably do something like this:

void Element::UpdateProperty(bool &property, bool newValue)
{
   property = value;
   Invalidate();
   // More code goes here. 
}

Now, we can implement Show and Hide, Flash, Unflash, Shaded etc by doing this, avoiding repetition inside each function.

void Element::Show()
{
    UpdateProperty(visible, true);
}

If the type isn't always bool, e.g. there is a position, we can do:

template<typename T>void Element::UpdateProperty(T &property, T newValue)
{
   property = value;
   Invalidate();
   // More code goes here. 
}

and the MoveTo becomes:

void Element::MoveTo(Point p)
{
    UpdateProperty(position, p);
}

Edit based on previously undisclosed information added to question:

Obviously the above technique can equally be applied to any form of function that does this sort of work:

void Element::SetVisible(bool value)
{
   UpdateProperty(visible, value);
}

will work just as well as for Show described above. It doesn't mean you can get away from declaring the functions, but it reduces the need for code inside the function.

like image 23
Mats Petersson Avatar answered Oct 17 '22 09:10

Mats Petersson