I recently had a debate with a co-worker about getter & setter which use pointers against a public member pointer (the topic results in the same debate without pointers and instead having a getter returning a reference). I'm not sure if this topic will be a duplicate, but while searching for an answer to the topic I found just three topics ( here, here and here) somehow related to the topic "getters/setters vs public member" without pointing into the direction as our debate went.
So here is the situation:
There is a class Text
. Objects of type Text
always contain another object of type TextProperties
(e.g. size, color, bold, italic, underline ect). To modify a property I wanted to do it directly using the methods of the TextProperties
-object without having the need to create a new object. This finaly resulted in a getter returning a pointer of the TextProperties
-object.
Here a very simple example of the situation:
//example for TextProperties
class TextProperties
{
protected:
int m_size;
bool m_bold;
public:
bool Bold() { return this->m_bold; }
void Bold(bool bold) { this->m_bold = bold; }
int Size() { return this->m_size; }
void Size(int size) { this->m_size = size; }
TextProperties()
{
this->m_bold = false;
this->m_size = 5;
}
~TextProperties() {}
}
//example for Text
class Text
{
protected:
TextProperties* m_properties;
public:
TextProperties* Properties() { return this->m_properties; }
void Properties(TextProperties* properties) { this->m_properties = properties; }
Text()
{
this->m_properties = new TextProperties();
}
~Text()
{
delete this->m_properties;
}
}
//the usage as I want it:
int main()
{
Text* exampleText = new Text();
//easily and short a property gets changed
exampleText->Properties()->Bold(true);
delete exampleText;
}
My co-worker argued against this solution because with that solution the door is opened to replace the object (also when using a reference-returning getter) while bypassing any setter.
//An example for the replacing bypassing the setter:
int main()
{
Text* exampleText = new Text();
//easily and short a property gets changed
exampleText->Properties()->Bold(true);
TextProperties* test = exampleText->Properties();
*test = *(new TextProperties());
//at this point the text wouldn't be bold
delete exampleText;
}
The only possibly safe solution (where the object can't be replaced with another) is as far as I know making the return const
and forcing anyone who uses this class to create a new TextProperties
-object for changing just one property. As mentioned this kind of solution is not wished.
//just as intimation how the other, replacing safe
//way of usage I want to avoid could look:
int main()
{
Text* exampleText = new Text();
//if needed copy-construct the object otherwise just use (default) constructor
TextProperties* newProperties = new TextProperties(exampleText->Properties());
newProperties->Bold(true);
exampeText->Properties(newProperties);
delete exampleText;
}
So far the situation - now the debate:
Accepting the goal to be able to modify the properties directly my co-worker than mentioned that the solution in his opinion has no difference to a public member.
My point of view is as follows:
- with the getter/setter the internals are hidden (=encapsulation)
- internal changes could be performed easier/faster as with public-member accesses scattered over all the source code
- also possibly ugly internal names with prefixes and/or suffixes are covered with a nice and easily describing name (e.g. internal: int m_x, m_y <-> external: Width(), Height() (yep people do things like that)) making code using the class more clear and easier to understand
- providing getter/setter the class-consumer can be sure that things are done in the way they should be done (public member for me only would make sense for simple types as int ect. since more complex objects maybe could need some specific actions e.g. for ensuring the correctness of the contained information) also the member is protected against modifications by mistake.
- if someone whants to replace the object while bypassing a getter he has to do it deliberate and thus it is his fault when the code does not work as expected, my task at this point only consists of ensuring that no corruption can happen (but that is anyway all the time my task) -> if you want force some things you can do... good or bad that's another question with that c++ does not deal, it just gives the possibilities ;)
- when avoiding by value objects don't need to be copied which can be but has not to be a performance gain (point added by edit)
- when accessing the object in editable way und change the members of the accessed object directly it is (for me) shorter und comprehensible source code (point added by edit)
I think the first two points are mainly arguments from the classic getter/setter vs public member discussions. Anyhow this arguments didn't change the opinion of my co-worker and I'm now brooding for days on this topic. So I'd like to know is there really no difference (I personally would definitely say "there is a difference") and the arguments are just my subjective opinion, is it a question of personal taste, do exist more convincing arguments (for both opinions) or exist completely different solutions which wouldn't cause this discussion?
Edit: additional to the questions I want to point more on the focus of my question (according to the first comment on the answer) and specify the question itself:
If the decision hast been made to have getters & setters and also breach the encapsulation with getters using reference or pointers: Why could/should this still be better than making the member a public member? (I tried to provide with the list arguments for having these getters and I'd like to know which of these arguments is in/valid or which other arguments could be pro/contra these getters or public member)
In hope that this is not a duplicate I expect some interesting answers. Thanks! :)