9

I've learn C++ for some time, however there is always this question which puzzles me (for years). In school, our lecturers like to declare class variables as private. In order to access it, we have to declare an accessor to access it.

Sometimes we even have to make the different classes become "friends" into order to access its elements.

My question is: Why make it so troublesome? What is the true rationale behind all the private and protected stuff when we can just make our life as a programmer easier by using public for everything?

I was thinking, once the code gets compiled, the end user will not even differentiate whether we use public or private in the back end coding, so why still need to declare it properly as private, protected...etc ?

user3437460
  • 17,253
  • 15
  • 58
  • 106
  • 1
    The less things that can change it, the less things to check when it has an unexpected value, and the easier it is for the class to assume its data isn't randomly changed (e.g., imagine if `vector`'s size was changed to be greater than the capacity). – chris Jul 09 '14 at 19:09
  • 1
    Google about encapsulation. – 101010 Jul 09 '14 at 19:10
  • 6
    Bro, its not about the end user....It is about you and other programmers. You will learn that all other programmers are evil and your future self is evil and will mess up your code. – Benjamin Trent Jul 09 '14 at 19:10
  • Private is for being able to sanitize the values going in. It is also for internal state which external users of the class shouldn't know about (ie: it is managed by the class). Most of the examples I recall seeing in University and school really didn't need private. Getters/Setters can be an unnecessary pain. – qeadz Jul 09 '14 at 19:10
  • "we can just make our life as a programmer easier". Go ahead. – n. m. could be an AI Jul 09 '14 at 19:13
  • Voting to re-open: I don't think this question is too broad, although answers would tend to be somewhat lengthy. – Sergey Kalinichenko Jul 09 '14 at 20:01
  • 2
    @BenjaminTrent +1. Never trust your future self. You can usually trust your past self, unless he/she is drunk. – JasonMArcher Jul 09 '14 at 20:21
  • Perhaps your question should be something like: Has the use of (only) private data attributes saved your code delivery dead-line? or provided any other benefits as a project coding standard? My team stuck to the 'private-data-attribute' rule on a bigger project, and I think I can describe how it did both. I would like this question reopened. – 2785528 Jul 09 '14 at 22:21
  • @DOUGLASO.MOEN Do you need me to edit my question before you give your solution below? thanks for reopening this. – user3437460 Jul 10 '14 at 10:34
  • @user3437460 - not necessary ... I'm on my 3rd rewrite, getting shorter every time. – 2785528 Jul 12 '14 at 01:38
  • Class its just because it have class I think. I only use struct, its public and less lines of code. – superbem May 30 '20 at 22:48

3 Answers3

9

To make your code easier to understand and maintain.

When you make a data member public, other programmers who use your class will naturally tend to use these public members rather than some member function that provides similar or the same information simply because it's easier. You might even tend to do this yourself. That's understandable -- programmers are inherently lazy beasts.

But suppose you realize somewhere down the line that the information that member function provides can no longer be generated from just that one member variable. Worse, what if that member variable becomes obsolete in the face of a design change. Worse still, what if the member variable itself isn't removed, but the semantics of it change.

Let;s consider an example. Say you have a class which represents items you have for sale:

class Gizmo
{
public:
  std::string mSku;
};

That's it, all you have is a sku. Suppose the contents of mSku are simply the product number, something like "12345".

You finish your code, ship it, and life's great. Until your company becomes as successful as Amazon, and now you start getting the same product from multiple vendors. You decide that the best thing to do is to encode the mSku so that it contains vendor information along with the produce number. The same widget from two different vendors might have very different skus: S:12345, Z:12345.

Any code that was written that expects mSku to be just a product number is now broken, and it will all have to be re-factored. In this silly little example it could be a problem. Imagine a codebase of 1 million lines of code -- not uncommon at all. You and all your coworkers have probably forgotten all about all the places where mSku is being used. None of the code will fail to compile, so the compiler's no help -- but all of that code is broken. This is a huge problem.

It would have been better at the outset if you hadn't relied on mSku at all, but provided a member function which was contracted to return the product number. Something like:

class Sku
{
public:
  std::string ProductNumber() const;
private: 
  std::string mSku;
};

Now you can change the semantics of mSku all you want. So long as you refactor what ProductNumber() does to return the product number, all those 1 million lines of code will still compile and still be correct.

In fact, I generally take this one step further. I will generally make everything in a class private until there is a specific reason to make it something else. Even then, I'll only make it protected unless I actually need it to be public.

[Why can't we] just make our life as a programmer easier by using public for everything?

In a large codebase, even if it's only maintained by one person, you actually make your life easier in the long run by making a lot of this stuff private from the very start.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    Thank you very much for your comprehensive explanation. Even in school, when I asked my lecturer similar question, he coundn't give a proper explanation. However, I will need to read your solution a few more times before I can understand it. :) – user3437460 Jul 09 '14 at 19:37
  • 1
    @user3437460: You're welcome. It's hard to really understand the benefit of doing things like this that seem to generate *more* work for you until you have been bashed in the head several dozen times through difficult and unfortunate experience. I could say, "just trust me, its easier this way." But you'll probably have to learn for yourself, just like I did. – John Dibling Jul 09 '14 at 19:39
  • That example doesn't really work though. The problem is people being muppets and relying on the `mSku` string being just a product number. Likewise, if anyone depends on `ProductNumber()` returning the full SKU string their code will also break when it changes. Seems like the actual solution is to add a separate `mProductNumber` variable to `Gizmo` (or better just make those muppets fix their broken code). – user673679 Apr 21 '19 at 17:39
  • @user673679: Your reference to "people being muppets" suggests to me that in your view what they are doing wrong is being lazy, and not inspecting library code or documentation about `mSku` before using `mSku`. They don't know what `mSku` is, so they shouldn't be using it. That latter point is probably true - a responsible programmer needs to know what `mSku` is before using it. The question really is, how should they be expected to figure out what `mSku` is? (continued) – John Dibling Aug 17 '19 at 17:24
  • @user673679: In my experience, programmers working on multi-million SLOC codebases aren't going to take the time to inspect some piece of library code before using that library. Ask yourself - have you really inspected the STL source code? Now we can get all mad and say "hey you didn't look at my code so you have no business using `mSku`" -- but 1) that's tilting at windmills, 2) it makes us bad citizens in the programmer community. The real solution is not to be offended that they didn't inspect your code. The real solution is to make it so they don't have to, by being semantically clear. – John Dibling Aug 17 '19 at 17:28
  • This is the most correct answer I have found so far. Thanks a lot @JohnDibling – wayne Jul 04 '23 at 07:44
5

You mark class members private: to reduce the number of things on which other developers who use your code may depend. The moment that you release your code for use by somebody else, everything that he can use becomes your maintenance liability. You cannot simply remove a public member function, or change its argument types, because doing so would break someone else's code.

That is why it makes sense to shrink the number of items that you must preserve, to give yourself more flexibility at changing implementation of your class. If a member is private, you are free to change or remove it without causing problems to other people who use your code. This is essential when you develop code in a team.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Can I presume if I developing my own program with only myself doing the coding, I can just declare everything as public? Or is there other benefits for a programmer to use private? I don't understand why is data hiding a benefit when user can't see the data anyway. Thanks for your reply! – user3437460 Jul 09 '14 at 19:17
  • 1
    @user3437460 Hiding implementation from yourself is as useful as hiding it from others. As your project gets bigger, you start making reusable libraries, which you link to several projects. If one project has a dependency on some member, you wouldn't be able to change that member for the benefit of other projects without having to fix the project that depends on it. On the other hand, if you are developing a small, self-contained project which you fully own, data hiding becomes an exercise in best practices, without much perceivable benefits. – Sergey Kalinichenko Jul 09 '14 at 19:23
  • 1
    @user3437460 If you are perfect and never make a mistake, then yes, you can presume so. Otherwise, no. Compile errors and type checking exists for a reason: to ensure your code is safe (under the assumptions which you have provided the type system) and contains no errors. – Konrad Rudolph Jul 09 '14 at 19:54
0

See C++ standard 11.1.

There is a philosophy behind object oriented design in c++.

Objects exist to provide portable functionality to the rest of your code. In order to make this possible, you should be able to specify how your objects are to be used by the next coder (even if the next coder is you).

In order to maintain that your object is strictly defined in the code for that class, it should present an interface to it's functionality. Usually this is just getters and setters. These are written so that in case you need to change how members are accessed, this is done in your class and no where else. To ensure this is the case, your member objects need to be private.

kwierman
  • 441
  • 4
  • 11