Search

8.3 — Public vs private access specifiers

Public and private members

Consider the following struct:

In this program, we declare a DateStruct and then we directly access its members in order to initialize them. This works because all members of a struct are public members by default. Public members are members of a struct or class that can be accessed from outside of the struct or class. In this case, function main() is outside of the struct, but it can directly access members month, day, and year, because they are public.

On the other hand, consider the following almost-identical class:

If you were to compile this program, you would receive errors. This is because by default, all members of a class are private. Private members are members of a class that can only be accessed by other members of the class. Because main() is not a member of DateClass, it does not have access to date’s private members.

Access specifiers

Although class members are private by default, we can make them public by using the public keyword:

Because DateClass’s members are now public, they can be accessed directly by main().

The public keyword, along with the following colon, is called an access specifier. Access specifiers determine who has access to the members that follow the specifier. Each of the members “acquires” the access level of the previous access specifier (or, if none is provided, the default access specifier).

C++ provides 3 different access specifier keywords: public, private, and protected. Public and private are used to make the members that follow them public members or private members respectively. The third access specifier, protected, works much like private does. We will discuss the difference between the private and protected access specifier when we cover inheritance.

Mixing access specifiers

Classes can (and almost always do) use multiple access specifiers to set the access levels of each of its members.

In general, member variables are usually made private, and member functions are usually made public. We’ll take a closer look at why in the next lesson.

Rule: Make member variables private, and member functions public, unless you have a good reason not to.

Let’s take a look at an example of a class that uses both private and public access:

This program prints:

10/14/2020

Note that although we can’t access date’s members variables m_month, m_day, and m_year directly from main (because they are private), we are able to access them indirectly through public member functions setDate() and print()!

The group of public members of a class are often referred to as a public interface. Because only public members can be accessed from outside of the class, the public interface defines how programs using the class will interface with the class. Note that main() is restricted to setting the date and printing the date. The class protects the member variables from being accessed or edited directly.

Some programmers prefer to list private members first, because the public members typically use the private ones, so it makes sense to define the private ones first. However, a good counterargument is that users of the class don’t care about the private members, so the public ones should come first. Either way is fine.

Structs vs classes revisited

Now that we’ve talked about access specifiers, we can talk about the actual differences between a class and a struct in C++. A class defaults its members to private. A struct defaults its members to public. That’s it!

Quiz time

1a) What is a public member?

Show Solution

1b) What is a private member?

Show Solution

1c) What is an access specifier?

Show Solution

1d) How many access specifiers are there, and what are they?

Show Solution

2) Write a simple class named Point3d. The class should contain:
* Three private member variables of type double named m_x, m_y, and m_z;
* A public member function named setValues() that allows you to set values for m_x, m_y, and m_z.
* A public member function named print() that prints the Point in the following format: <m_x, m_y, m_z>

Make sure the following program executes correctly:

This should print:

<1, 2, 3>

Show Solution

3) Now let’s try something a little more complex. Let’s write a class that implements a simple stack from scratch. Review lesson 7.9 -- The stack and the heap if you need a refresher on a what a stack is.

The class should be named Stack, and should contain:
* A private fixed array of integers of length 10.
* A private integer to keep track of the length of the stack.
* A public member function named reset() that sets the length to 0 and all of the element values to 0.
* A public member function named push() that pushes a value on the stack. push() should return false if the array is already full, and true otherwise.
* A public member function named pop() that pops a value off the stack and returns it. If there are no values on the stack, it should assert out.
* A public member function named print() that prints all the values in the stack.

Make sure the following program executes correctly:

This should print:

( )
( 5 3 8 )
( 5 3 )
( )

Show Solution

8.4 -- Access functions and encapsulation
Index
8.2 -- Classes and class members

51 comments to 8.3 — Public vs private access specifiers

  • vinoth

    by default class is public or private in c++

  • Spock

    Another great tutorial. You write really well man.

  • Joseph

    Does C++ only accept class members declared with the public:, private: and protected: access specifiers?
    Would writing them like this also work?

    • C++ newbie

      I just tried compiling that and it didn’t work.  It said that it needed the colon after public.  I know you can declare things like this in other languages, though (like Java)

  • Marvin

    I’m missing the quizzes to apply my just received knowledge like in former chapters!

  • Nate

    I did not struggle with c++ at all until I hit classes.  I have been stuck on them for a week now and feel that I am making very little progress.  Is that normal for most people?  Thankyou

    • Alex

      Yes, making the shift from normal functions to objects can be a little hard to wrap your brain around. But once you “get it”, you won’t want to go back.

      What specifically are you stuck on?

  • I have few questions Alex…

    In the previous lesson you said that structs can’t include functions. In this lesson I have a confusion with this line:

    "One of the primary differences between classes and structs is that classes can explicitly use access specifiers to restrict who can access members of a class"

    The following program works fine:

    I can define a function inside a struct. I can strict members using public and private. Till this point, I only can see a single difference between struct and classes that class members are by default private and struct members are public. Are we missing something???

    The wikipedia also has an article containing an example where struct is used and shown that its members are restricted.

    https://en.wikipedia.org/wiki/Access_modifiers

    • Alex

      Yes, the previous statement was misleading (and has been corrected) -- the intent was to say that data-only structs were non-object-oriented, not all structs. In C++, structs are like classes where all the members are public by default.

  • Colleen

    I’m very glad you include sample code.

    What IDE are you using to compile and run your code? I have NetBeans installed on my computer, and I tried to run the “employee” example program, but I got compilation errors (“‘cout’ is not a member of ‘std'”). Do you recommend NetBeans-or do you have an IDE you’d recommend?

    Thanks!

    • Alex

      NetBeans is okay, but it sounds like your compiler is out of date. NetBeans has support for multiple compilers -- maybe you can change to a more modern compiler version.

  • Batyr

    Hey, Alex! Could you please explain me why if m_length is equal to 10 return false? why not 9?

    for example, if length is already 9, it will continue to the next statement, and how it is going to assign [m_length++] => [10] to the array? if subscripts are from 0 to 9? Or maybe bcz of increment operator order?

    Thanks!

    • Alex

      We used the postfix increment operator here, not the prefix increment operator. So m_length isn’t incremented until after it’s evaluated.

      So when m_length is 9 and the function is called:

      is essentially the same as:

      You can see that m_length is evaluated to be 9 first, then it’s incremented to 10.

      And if m_length is 10, that’s an invalid index for our array, so we ignore the push request so we don’t walk off the end of the array.

  • BlueTooth4269

    Isn’t static technically an access specifier if you’re defining your class in another cpp file?

  • sitaram chhimpa

    Can anyone suggest while below code is not working for 3rd question …it is giving me initial len as -2 while initilized by 0 in reset function.

    • Alex

      you’re not initializing your member variable len, you’re initializing a new local variable with the same name instead.

      Remove the int prefix so it knows you mean member variable len instead of a new local variable.

  • John Mounir

    this is extremely helpful tutorial, Thank you so much.

  • P

    shouldn’t it be

    if we want to return the popped valued?

    • Alex

      No. As implemented, length holds the index of the next free element (which is one element past the top of the stack). Therefore, we need to first decrement (to get to a valid element) and then evaluate.

  • Shiva

    Hi Alex, I have a couple of questions:

    * Use of private: in class declarations given in the quiz solutions is superfluous. Is it just for demonstration or is that a programming practice?
    * This might sound a bit dumb: is it preferable not to prefix public member functions with m_ ?

    In Quiz #3, you didn’t specify what pop() should return if there are values on the stack.

    BTW nice lesson, I liked the quiz questions very much. Brilliant! 🙂

    • Shiva

      Sorry, I meant to ask: is it preferable not to prefix public members with m_ ? If it is only for private members, then what about private member functions (if any)?

      • Alex

        By common convention:
        All public and private member variables should be prefixed by m_ (unless they are static, in which case they should use s_).
        All public and private member functions should not use a prefix.

    • Alex

      1) Yes, explicitly declaring private can be superfluous. However, I always add it, both because it makes my intent explicit, and that way, if I later decide to add something public above it, I don’t risk accidentally making all of the members that were implicitly private now public. Since there’s no performance penalty for doing so, I like being a little defensive here.
      2) Usually only member variables are prefixed with m_. Member functions typically aren’t, regardless of whether they’re public or private.
      3) I’ve updated the instructions to be explicit about what pop() should return. Thanks for pointing that out.

  • T

    Aha!! I did it all with std::array only to find out that it would not work!

  • Jim

    Alex,
    In this exercise.

    Moot point, why make a class Point3d private, when your using all three of its members variables as input in the two public functions.

  • Nyap

    so are enumerations in an enum class private/protected

  • Vijin

    At this point,

    does it only add a value into the array, or does m_length get incremented too? I can’t see an association of m_length to the actual length of the array.

  • Vijin

    Thank you Alex! I really need to brush up on the basics again before going any further.

  • Rob G.

    Dear Alex,

    This was a bear of an assignment to say the least. After doing it I was so glad we have stack, vector containers. I couldn’t help feeling that the solution was a "DIY" stack build. I see that every pop/push call is constructed in a "raw" manner in a class that is user made. There are no container members to use except what the user programs as a member functions in the class. What we see in the stack we are allowed to see is created by moving the length up and down in a sort of roving window. Just a suggestion maybe you could add a hint in the exercise to not use available containers. That would have saved me considerable time trying to determine which container (in this case none or made from "scratch") to use. Also, if you use a for each loop in pop/push/reset u break this delimiter based stack by seeing the whole array all the time with numbers to 10. For e.g. the stack is the same all the time if u print it out with a for-each loop. Anyway I learned an awful lot but was a little disappointed I actually had to consult the answer.

    Can u plz tell me why I am getting a one-off on line 32?

    • Alex

      I’ve updated the quiz instructions to note that you’ll be doing this from scratch.

      Your code is slightly wrong because your push does a pre-increment on length instead of a post-increment. This means your stack effectively starts at array index 1 instead of 0, which is why you’re having to offset your array indices in function print().

  • Kattencrack Kledge

    About the reset() function in the last quiz question:

    Is it okay/good practice to do it this way:

    I wanna be really sure that it’s ok to do that. Sorry for the bombarding questions.

  • Mauricio Mirabetti

    Alex, I tried to do something less magic numbers oriented related to length, with the following:

    , and using m_capacity throughout the code.
    At compile time, got: "a nonstatic member reference must be relative to a specific object". The only solution was to use "static constexpr" instead of const.
    Why’s that again? I’m sorry if this was covered, couldn’t find the answer on previous chapters.
    Thanks a lot.
    Mauricio

    • Alex

      m_capacity isn’t actually initialized until the object of the class is instantiated, which makes m_capacity a runtime constant, whereas arrays require a compile-time const.

      What’s interesting is that you CAN use an enumerator (replace your const int m_capacity with “enum X { m_capacity = 10 };” and it will work), since enumerator values are defined at compile time.

  • Robby

    shouldn’t this be:

    so that pop() returns the value it has just popped?

    • Alex

      Nope. In the provided solution, m_length always contains the index of the next FREE element on the stack (not the last valid element). So to return the last valid element, we need to first decrement m_length and then return the value.

      • Matthew senko

        hey can you explain this more? pop() is the only part i dont 100% understand. I see that it is taking a int off the ‘stack’ but how is it doing it?

        • Alex

          Since this seems to be generating a lot of questions, I’ve updated the example in a few ways:
          1) I’ve changed the name of m_length to m_next, which makes a lot more sense since it’s holding the index of the next free element, not the length of the array. Bad variable naming on my part!
          2) I added a bunch of annotative comments to help people understand what’s happening.

          Have a look over the solution and let me know if that helps.

  • Sivasankar

    A small typo error in line 16 in solution of problem 3 in Quiz section. I think it should be m_array instead of m_next to set array elements to ‘0’

  • Matt

    In your stack quiz solution, you included header file <assert> rather than <cassert>.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter