13

I came across this during his stream, and this stuck out to me like a sore thumb since. I thought maybe if I saved the video and come back to it in the future when I'm more proficient I'll understand it, but it just kept on bothering to just leave it be. Here's the video...

It automatically starts at 1:13:00 for you.

https://youtu.be/uHSLHvWFkto?t=4380

As a new programmer to C/C++ after hearing this its completely warped my way of thinking. With him being a professional and all I should take the advice, but I need some clarity. From sites, videos, to books, I've read that the use of public variables is a bad practice, but from what I'm getting from this video its saying otherwise. In the video he's uses a struct which by default has a access modifier of "public" vs a class which has a default access of "private". Is there something I'm not comprehending properly here.

I don't know what to do. If I make my variables public won't I risk ambiguity ? The way he's saying that he'll automatically fire someone for coding in format is getting to me haha! Which one should I truly use ? When and Why ?

PrimRock
  • 1,076
  • 2
  • 15
  • 27
  • Getters and Setters are good when you want to avoid modifications on your members without any control. I think it's a little bit overused, some cases public variables are acceptable, but for big classes it's problematic because when somebody want to get some information, he will just search for the Getters and won't check if there are any public variable... so my advice: Be careful with it, but rarely public variables are okay. – Melkon Sep 17 '15 at 08:06
  • @TonyD: If i would write an answer i would write examples etc... this is just some short thoughts came to my mind. – Melkon Sep 17 '15 at 08:10
  • 1
    Possible duplicate: http://stackoverflow.com/questions/2977007/public-data-members-vs-getters-setters?rq=1 – Tony Delroy Sep 17 '15 at 08:36
  • 1
    [`std::pair`](http://en.cppreference.com/w/cpp/utility/pair) have `first` and `second` with public visibility and is from the standard itself. IMHO in objects which only holds data (without behaviour) making getters and setters is more a burden than an advantage. – PaperBirdMaster Sep 17 '15 at 08:48
  • 2
    Why was this put on hold? The question is **not** "primarly option based"! – 3442 Sep 17 '15 at 09:04

4 Answers4

17

In my experience people use getters/setters excessively for no good reason.

One can think of two major kinds of classes: the ones grouping together related data and the others providing behaviour.

Behaviour classes must be encapsulated with no public data members.

Data classes normally should have data members public and no behavior.

The grey area between these two is mutable data classes with invariants or dependencies between members, e.g. if member a is 1, then member b must be in range [1-10]. For such cases usage of getters/setters may be justified. For immutable data classes the constructor must establish the invariant.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 5
    "In my experience people use getters/setters excessively for no good reason." Amen to that. Folk too often do it without realising it circumvents encapsulation. – Bathsheba Sep 17 '15 at 08:09
  • Good answer but "In my experience people use getters/setters excessively for no good reason" is sticking out. It's more of an opinion. My take is that excessive use of accessors is what is taught to students early on in the courses and classes and that is what most programmers bring in "the real world". That and that most programmers usually are not "good programmers" and do not think things through and just do what they are told. – Rade_303 Sep 17 '15 at 08:51
  • 1
    @RockyMM _It's more of an opinion_ - you are spot on, this is why I started it with _In my experience..._ – Maxim Egorushkin Sep 17 '15 at 08:53
  • @MaximEgorushkin I understand. But the thing is that the rest of the answer is spot on and has perfect sense and is not an opinion. It's kind of... mixed to me. It kind of prepares the reader that you are somehow _against_ accessors, when you are not - "Data classes normally should have data members public and no behavior". Dunno, it's just me probably. :) – Rade_303 Sep 17 '15 at 08:56
14

First of all, a struct is completely equivalent to a class, but with the default member access being public rather than private.

Now, in Object Oriented Programming (OOP), it's not considered good practice to have public data members (variables), because that makes all your code dependent on the internals of the class, and thus breaking a primordial principle of OOP, and that is...

Holy and Sacred Encapsulation

Encapsulation is the coding philosophy that states that a class should englobe both data and the code that manages it in a single tight entity. That is, you don't access data directy, but rather you use methods from the class to manipulate such data. This has several design advantages, such as that you'll know that no code except the one inside the class may incorporate bugs with respect to the manipulation of such information.

Now, get()ers and set()ers, otherwise known as accessors, are a complete lie! With accessors, you're tricking yourself into thinking that you're respecting encapsulation, when you're rather breaking it! It adds bloat, unnecessary verbosity, bugs, and everything but encapsulation. Instead of having a class Person with unsigned getAge() and void setAge(unsigned), have it with a unsigned getAge() and a void incrementAge() or however you want to call it.

Now, to your question's core...

"Plain old" structs

Encapsulation is not always desired. Although you should (usually) not do this on header files (again, for at least some bit of encapsulation), you may create static plain old structs that are private to a single translation unit. My recommendation is to make them even "older" than they already are, i.e...

  • All data members are public.
  • No methods.
  • No constructors (except implicit ones).
  • Inheritance is always public, and only allowed from other plain old structs.
  • I repeat, don't put them on header files!

Now, another use for plain old structs is (ironically) metaprogrammatic exporting of constexpr data and types, otherwise known as modern-hardcore-template-metaprogramming-without-having-to-type-public-everywhere, for example...

template<bool B, typename T>
struct EnableIf {};

template<typename T>
struct EnableIf<true, T> {
    typedef T type;
};

template<bool B, typename T>
using SFINAE = typename EnableIf<B, T>::Type;
anastaciu
  • 23,467
  • 7
  • 28
  • 53
3442
  • 8,248
  • 2
  • 19
  • 41
  • 1
    ... Can the downvoter give me his/her reasonings for it? – 3442 Sep 17 '15 at 09:06
  • @KemyLand You might be upsetting atheists with your wording :) – Maxim Egorushkin Sep 17 '15 at 10:12
  • @MaximEgorushkin: Of course may they :). – 3442 Sep 17 '15 at 10:26
  • @KemyLand Ok, I gotta a little better insight, but how should avoid using them when modeling real world objects. Every tutorial I came across talks about them, but ever since I came across that video i feel like I've been lied to. Is there any book you can recommend on approaching objects and modeling them with good structure ? – PrimRock Sep 17 '15 at 16:51
  • 1
    @IZUHU: You've not (precisely) been lied by such a video (p.d: I've not seen it completely), but, if the video uses `struct` for non-"plain old struct" purposes, then that's not good. I cannot recommend you any books, because I haven't really read any about programming/coding principles. I usually find everything I need from Google and SO :). Maybe someone else can recommend you any book? – 3442 Sep 18 '15 at 00:19
5

It's certainly difficult to control the internal consistency of your object if you make the data members public.

What works well is to use constructors to set up the state of an object, then use public functions to retrieve values of member variables, but only if that's needed. If you need to mutate the object after construction, then provide very specific methods for that purpose.

If, however, your object is no more than something that aggregates orthogonal data types, then use public access for all members: a struct works well for that.

Note that the only difference between a struct and a class is that in the former, the default access is public whereas in the latter it is private.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
-1

If you keep your data members private then you can easily control about accessing their value. For example you have age variable in your code.

public:
int age;

Now someone outside your class can easily change value of age, may also assign illegal value, for example age = -10. But your logic suggests age cannot be negative, so best practice is to keep variable private, and give some function which will assign value to your variable.

private:
int age;

public:
void setAge(int age)
{
 if (age > 0)
   this->age = age;

}
Pranit Kothari
  • 9,721
  • 10
  • 61
  • 137
  • That could introduce undefined behaviour: (1) instantiate your object, (2) call setAge with a negative value, (3) read back `age`. (4) watch your computer melt since you're reading an uninitialised value. – Bathsheba Sep 17 '15 at 08:13
  • I think the question is about the situations, when the setter do nothing, just set a new value. – Melkon Sep 17 '15 at 08:14
  • 1
    @Bathsheba: how do you know age is uninitialized? we do not see the constructor and the `int age` variable is the member, not the variable that will be passed. @ Pranit Kothari: I think another example would be better, e.g. passing a string and checking if it is an existing file. Your case can be avoided by simply using unsigned int. – Gombat Sep 17 '15 at 08:15
  • 1
    @Bathsheba You are right, I have not provided complete code but pseudo code. With constructor I could take care of initilization. – Pranit Kothari Sep 17 '15 at 08:15
  • I'm simply pointing out that you need to be *extremely* careful with code like this. That said, I've changed would to could. – Bathsheba Sep 17 '15 at 08:17
  • 1
    @Gombat True. My case will be solved by unsigned int, just trying to make a point. – Pranit Kothari Sep 17 '15 at 08:17
  • 1
    As usual :-) examples of setters are not very good examples. If this is part of some Person class, there is no need for a `setAge` functions, as that is not how age works - it doesn't change randomly. You might have a `void CelebrateBirthday() {++Age;}` to model the Person getting older. The age never changes by -10 or +2, always by +1. – Bo Persson Sep 17 '15 at 08:59