Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

About getters/setters

50 views
Skip to first unread message

JiiPee

unread,
Aug 21, 2019, 3:23:08 PM8/21/19
to
Which one is better:

1)

class Person

{

public:

int getAge() { return age;}

void setAge(int a) { age = a;}

private:

int age;

};

or

2)

struct Person

{

int age;

};

####

I know Herb Sutter recommended 1) but for example isocpp

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-get

seems to recommend 2). Herb says that for example when debugging 1) is
good because you can write to file all the accesses of the age, or cout
all the calls. Also debugger can stop at the function call, but can
debugger stop at :

person.age = 6;

?

So debugger can put a red dot to setAge and see which object changed it.
And cout/write on file information.

Argument also, that later on can add other functionality punder setAge
(like cache logic).

But 2) people argue its so simple and not likely to change, so it breaks
OO idea.

I do currently 1) but wondering which way to go.

Like now I have a "Settings" class. Simple data members. I started
adding getters and setters....

Jorgen Grahn

unread,
Aug 21, 2019, 3:34:32 PM8/21/19
to
On Wed, 2019-08-21, JiiPee wrote:
> Which one is better:
>
> 1)
>
> class Person
> {
> public:
> int getAge() { return age;}

There's a const missing.

> void setAge(int a) { age = a;}
>
> private:
> int age;
> };
>
> or
>
> 2)
>
> struct Person
> {
> int age;
> };

Or one which is not invalidated by time itself:

struct Person {
explicit Person(const Date& birthday);
const Date birthday;
};

(Ignoring intricacies of hours, minutes and time zones, and people of
unknown age.)

It depends on what you're modeling and how you want to model it.
Saying one is better than the other is like saying a spoon is better
than a fork.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Bo Persson

unread,
Aug 21, 2019, 3:41:03 PM8/21/19
to
There probably isn't a general answer, except that it depends.

If you model a real person, the age doesn't change except by +1 on each
birthday. So what is the use for setAge?


In the Core Guidelines you have a Point(x, y) where it is unclear what
the use for set_x is. So you could just skip it.

If the class were to have some kind of behavior, perhaps a
Point.move_to(somewhere) would be more useful?


So, it depends. :-)


Bo Persson

Öö Tiib

unread,
Aug 21, 2019, 3:52:22 PM8/21/19
to
On Wednesday, 21 August 2019 22:23:08 UTC+3, JiiPee wrote:
> Which one is better:
>
> 1)
>
> class Person
>
> {
>
> public:
>
> int getAge() { return age;}
>
> void setAge(int a) { age = a;}
>
> private:
>
> int age;
>
> };
>
> or
>
> 2)
>
> struct Person
>
> {
>
> int age;
>
> };

Age is rapidly changing property of a person so it is usually made as
getter function that calculates it based on date of birth of person
and current date. Date of birth is usually const set in constructor
since that can't change during life-time (or even after) of a person.

Snipping possible misrepresentation of Herb Sutter and
CppCoreGuidelines of isocpp.

> I do currently 1) but wondering which way to go.

I think you should do in usual way (that I desribed).

JiiPee

unread,
Aug 22, 2019, 10:25:24 AM8/22/19
to
On 21/08/2019 20:52, Öö Tiib wrote:
> Snipping possible misrepresentation of Herb Sutter and
> CppCoreGuidelines of isocpp.


Sutter says like: "Always make all data members private. The only
exception is c-style struct where all members are public"

So he was against putting some private and some public. And he proves
his point.

So according to him if Person class has some functions (like increasing
the age automatically) then the age itself should be private and if its
value is needed we need a getter.

Öö Tiib

unread,
Aug 22, 2019, 12:06:52 PM8/22/19
to
On Thursday, 22 August 2019 17:25:24 UTC+3, JiiPee wrote:
> On 21/08/2019 20:52, Öö Tiib wrote:
> > Snipping possible misrepresentation of Herb Sutter and
> > CppCoreGuidelines of isocpp.
>
>
> Sutter says like: "Always make all data members private. The only
> exception is c-style struct where all members are public"

CppCoreGuidelines at
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-get>
does not conflict with it just suggest to prefer that c-style struct
to all trivial setters and getters. That is why your claim seemed
misrepresentation.

> So he was against putting some private and some public. And he proves
> his point.

Your OP did not discuss putting some data members private and
some public, both are against it:
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c134-ensure-all-non-const-data-members-have-the-same-access-level>

> So according to him if Person class has some functions (like increasing
> the age automatically) then the age itself should be private and if its
> value is needed we need a getter.

What you seemingly asked in your OP was if to have trivial setters
and getters or to have c-style struct. "Getter" is red herring
since you don't need one with c-style struct.

Tim Rentsch

unread,
Aug 22, 2019, 6:09:27 PM8/22/19
to
JiiPee <n...@notvalid.com> writes:

[some white space reformatting done]

> Which one is better: 1)
>
> class Person {
> public:
> int getAge() { return age;}
> void setAge(int a) { age = a;}
> private:
> int age;
> };
>
> or 2)
>
> struct Person {
> int age;
> };
>
> ####
>
> I know Herb Sutter recommended 1) but for example isocpp
>
> https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-get
>
> seems to recommend 2). [...]
>
> I do currently 1) but wondering which way to go.
>
> Like now I have a "Settings" class. Simple data members. I started
> adding getters and setters....

I agree with Herb Sutter's recommendation that (assuming the
class or struct has some member functions) data members should
never be public. There are cases where for data members might
plausibly be made protected rather than private, but never
public. (Incidentally I am ignoring the "age/birthday" matter
that some other people have commented on, and assuming your
question is meant as generic, with 'age' being merely an
unfortunate choice of example.)

I suggest however a slightly different pattern than (1), along
these lines (disclaimer: not compiled):

class Person {
unsigned siblings_;
// ... other data members ...

public:
// ... other member functions

unsigned &siblings() { return siblings_; }
const unsigned &siblings() const { return siblings_; }
};

Now our accessor functions look more like data member access, but
they remain functions:

if( fred.siblings() > 0 ) ...

fred.siblings() += 1; // a new birth in fred's family

To me this pattern reads nicer on the client side than set/get
functions.

Ian Collins

unread,
Aug 23, 2019, 12:17:10 AM8/23/19
to
There is a case where a data member is safe to be public: a const data
member. Access to such a member cannot change a class's invariants.

--
Ian.


JiiPee

unread,
Aug 23, 2019, 2:10:03 AM8/23/19
to
On 22/08/2019 23:09, Tim Rentsch wrote:
> (Incidentally I am ignoring the "age/birthday" matter
> that some other people have commented on, and assuming your
> question is meant as generic, with 'age' being merely an
> unfortunate choice of example.)


correct. the example given might not have been the best. general
question about all situations.


>
> I suggest however a slightly different pattern than (1), along
> these lines (disclaimer: not compiled):
>
> class Person {
> unsigned siblings_;
> // ... other data members ...
>
> public:
> // ... other member functions
>
> unsigned &siblings() { return siblings_; }
> const unsigned &siblings() const { return siblings_; }
> };
>
> Now our accessor functions look more like data member access, but
> they remain functions:
>
> if( fred.siblings() > 0 ) ...
>
> fred.siblings() += 1; // a new birth in fred's family
>
> To me this pattern reads nicer on the client side than set/get
> functions.


yes many seems to suggest this online



JiiPee

unread,
Aug 23, 2019, 2:13:25 AM8/23/19
to
On 22/08/2019 23:22, Stefan Ram wrote:
> Instead of asking the object for data and the processing
> to data outside of the object (as when using accessors),
> you should tell the object to do the processing itself.


sometimes its about storing global settings like:

struct Settings

{

Color backgroundColor;

int fontSize;

....

};


So I guess this class is not really meant to operate with the values
only return them? it just bundless a group of data.

David Brown

unread,
Aug 23, 2019, 3:30:41 AM8/23/19
to
Classes like that still need to have protection. There may not be need
for synchronisation between members for keeping invariants, but usually
you don't want to allow any possibility of other parts of the code
making uncoordinated changes to the values.

Jorgen Grahn

unread,
Aug 23, 2019, 7:24:51 AM8/23/19
to
On Thu, 2019-08-22, Stefan Ram wrote:
> Supersedes: <accessor-20...@ram.dialup.fu-berlin.de>
> [Typos and clarifications]
>
> JiiPee <n...@notvalid.com> writes:
>>int age;

> A class needs to protect its invariants.
>
> Therefore, a member can be public only if it is not
> mentioned in an invariant of the class.

I think invariants (explicit or implicit) is why setters and getters
bother me.

Either you have a C struct with no invariants, and setters/getters are
just unnecessary OO noise on top of non-OO code.

Or you /do/ have invariants, and setting an individual member, at any
time, threatens to break the invariant. Which doesn't mean there can
be /no/ set/get methods, they won't map 1:1 to the members.

> An accessor, however, is just appropriate for data
> classes where objects effectively are used to represent
> records as in non-OOP programming. In OOP they violate
> "Tell, Don't Ask!".
>
> Instead of asking the object for data and then processing
> the data outside of the object (as when using accessors),
> you should just /tell the object/ to do the processing.

Moving logic into the class instead of treating it like a dumb
container. Also good advice (except of course when you /want/
a dumb container).

Tim Rentsch

unread,
Aug 23, 2019, 8:26:21 AM8/23/19
to
My experience with const data members is that they are almost
always more trouble than they're worth. Even in those cases
where a data member is made const, it's better to stick to the
simple rule that data members (other than pure structs) never be
public, on general principles of information hiding: client code
shouldn't know or care what particular data members a class has,
let alone whether they are const or not. Any property an object
wants to supply to its clients should be made available through a
(usually const) member function, and only that, regardless of
whether the property needs an elaborate computation or is simply
returning the value of a data member -- even a const one.

James Kuyper

unread,
Aug 23, 2019, 8:34:34 AM8/23/19
to
On 8/23/19 7:24 AM, Jorgen Grahn wrote:
...
> I think invariants (explicit or implicit) is why setters and getters
> bother me.
>
> Either you have a C struct with no invariants, and setters/getters are
> just unnecessary OO noise on top of non-OO code.
>
> Or you /do/ have invariants, and setting an individual member, at any
> time, threatens to break the invariant. Which doesn't mean there can
> be /no/ set/get methods, they won't map 1:1 to the members.

In general, I agree. However, a setter for a single member could make
sense, if the applicable constraints allow two or more different values
for that member, even if all other members are unchanged. For instance,
the invariant might be current_value <= maximum_achieved_value. The
setter for current_value would deal with changes that would violate that
invariant, either by rejecting them or by increasing
maximum_achieved_value (which corresponds to the last case you mention:
a setter that changes two or more members in synchrony).

Jorgen Grahn

unread,
Aug 23, 2019, 10:48:41 AM8/23/19
to
On Fri, 2019-08-23, Stefan Ram wrote:
> James Kuyper <james...@alumni.caltech.edu> writes:
>>On 8/23/19 7:24 AM, Jorgen Grahn wrote:
>>>Or you /do/ have invariants, and setting an individual member, at any
>>>time, threatens to break the invariant. Which doesn't mean there can
>>>be /no/ set/get methods, they won't map 1:1 to the members.
> ..
>>invariant, either by rejecting them or by increasing
>>maximum_achieved_value (which corresponds to the last case you mention:
>>a setter that changes two or more members in synchrony).

When I wrote "map 1:1 to the members" I was more thinking of someone
going through all the members and adding a setter for each of them.

> Behind all of this lurks the question: How does one define "setter"?

How about "a method that's defined in terms of changing a certain part
of the object, without considering the object as one single entity"?

But I suppose that's my definition of a setter I dislike, rather than
of all setters.

Jorgen Grahn

unread,
Aug 23, 2019, 11:49:22 AM8/23/19
to
I can imagine how that could end up with me breaking out:

ValueWithHighwatermark<int> foo = 2; // 2, 2
foo = 3; // 3, 3
foo = 0; // 0, 3

I know it was just an example, but my gut feeling is that there
are often solutions like that: to raise the abstraction level
of the members.

Melzzzzz

unread,
Aug 23, 2019, 2:07:50 PM8/23/19
to
Also there is case when member is class with own interface.


--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Tim Rentsch

unread,
Aug 24, 2019, 7:33:01 AM8/24/19
to
Tiib <oot...@hot.ee> writes:

> On Thursday, 22 August 2019 17:25:24 UTC+3, JiiPee wrote:
>
>> On 21/08/2019 20:52, Tiib wrote:
>>
>>> Snipping possible misrepresentation of Herb Sutter and

Strange comment considering that nowhere in the thread is any
reference given for Herb Sutter's views. Given that you don't
know what Herb Sutter writings JiiPee means to refer to here,
there is no basis for claiming a misrepresentation, or even
a possible misrepresentation (except in the vacuous sense that
"all things are possible").

>>> CppCoreGuidelines of isocpp.
>
>> Sutter says like: "Always make all data members private. The only
>> exception is c-style struct where all members are public"
>
> CppCoreGuidelines at
> <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-get>
> does not conflict with it just suggest to prefer that c-style struct
> to all trivial setters and getters. That is why your claim seemed
> misrepresentation.

For what it's worth, I think JiiPee's comments offer a more
faithful representation of the core guidelines document than
yours do.

Jorgen Grahn

unread,
Aug 25, 2019, 2:16:51 AM8/25/19
to
Personally, for a config struct I'd ask myself "will I create this
object early and pass it once to the main application logic?". If the
answer is 'yes', I'd happily pass it as const and leave it as it is.

David Brown

unread,
Aug 25, 2019, 6:13:07 AM8/25/19
to
That could well be sufficient protection, yes.


0 new messages