I struggle with this question very often and couldn't find any clear solution. I think I know the motivation of getters/setters.
Prior Information:
When realizing real life data, usually the data is encapsulated in more than one layers. For example:
// 1st stage data types ------------------------------ struct Cartesian { int32_t x; int32_t y; int32_t z; } struct GeoLocation { double_t latitude; double_t longitude; int32_t altitude; } // 2nd stage data types ------------------------------ struct Drone { Cartesian baseOffset; // m Cartesian velocity; // m/s } struct Plane { GeoLocation location; // semicircle Cartesian velocity; // knots } // 3rd stage data types ------------------------------ struct Swarm { Plane base; Drone member[10]; }
In C++, I use classes instead of structs (because why not?). And the problem arises when a data about Swarm[3].member[8].velocity.x
is received over some communication channel. Realize that there can be more than one swarm in a system.
Requirement:
By MISRA C++ rules, a function cannot return non-const reference to any class-member because the member should not be changed without that class' permission/knowledge.
Question:
When I use getters and setters, I cannot say "Swarm[3].member[8].velocity.x
"; instead I may say this in several ways:
1. This is not allowed as get() functions returns const reference and cannot call set().
Swarm[3].getMember(8).getVelocity().setX(5)
; (orset("X", 5)
)
2. This method carries all burden into the Swarm class. Although the code seems shorter for who is calling Swarm class, it is very heavy to code and to do maintenance in the background in case of a change.
Swarm[3].setMemberVelocity(8,X,5)
3. This method is somewhat in between, but here the problem is you might be sacrificing efficiency because every time a new data arrives first you create a temporary variable, get it, fill it and set it.
Cartesian tempVelocity = Swarm[3].getMember(8).getVelocity();
tempVelocity.x = 5;
Swarm[3].setMemberVelocity(8, tempVelocity);
Which one of these 3 methods are the best? Or are there any alternatives that I might use?
Thanks in advance.
As mentioned earlier, the primary use of setter and getter is to maintain encapsulation. We require a setter method to update the value of a private variable from outside of the class and a getter method to read the value of that variable.
The name of the property to bind to the given function. An alias for the variable that holds the value attempted to be assigned to prop . You can also use expressions for a computed property name to bind to the given function. In JavaScript, a setter can be used to execute a function whenever a specified property is attempted to be changed.
When current is assigned a value, it updates log with that value: Note that current is not defined, and any attempts to access it will result in undefined . To append a setter to an existing object, use Object.defineProperty () . Tip: you can click/tap on a cell for more information. Has more compatibility info.
To avoid repeating the check, you can use setters and getters. The getters and setters allow you to control the access to the properties of a class. A getter method returns the value of the property’s value. A getter is also called an accessor. A setter method updates the property’s value. A setter is also known as a mutator.
I may not know MISRA to a full extent. However, it seems like it is counter-productive to a flexible design (and not at all c++ish). Suppose I find out I need:
struct SuperSwarm {
Swarm swarms[10];
};
Then following your option 2, I would need to implement a host of setters/getters for all the inner aggregates, since it sounds somewhat like in your case you need to be able to set all data individually. The same thing happends if you need to change something in Drone
then everything needs to be updated. For a good and flexible design you can see how this is a nightmare really. There is not really a good alternative abiding by the rules you set out. That is why you usually return a non-const reference and use that if you don't need special handling. That, in some ways, future-proofs your code as opposed to just a public member variable.
One way you could 'cheat' (and use your option 3) and still be flexible design-wise is to proxy everything - like for example a std::shared_ptr
. When you return a std::shared_ptr
it seems like it is a copy and it is - but its actually just a proxy to the same pointed to object (which is similiar to how things work under the hood in some other OO programming languages). You may need a more appropriate proxy class though. But then again why bother ? why not just use structs and say it is a data structure and not some class holding (another) responsibility. After all, then you would express your intent clearly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With