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.

Access controls work on a per-class basis

Consider the following program:

One nuance of C++ that is often missed or misunderstood is that access control works on a per-class basis, not a per-object basis. This means that when a function has access to the private members of a class, it can access the private members of any object of that class type that it can see.

In the above example, copyFrom() is a member of DateClass, which gives it access to the private members of DateClass. This means copyFrom() can not only directly access the private members of the implicit object it is operating on (copy), it also means it has direct access to the private members of DateClass parameter d! If parameter d were some other type, this would not be the case.

This can be particularly useful when we need to copy members from one object of a class to another object of the same class. We’ll also see this topic show up again when we talk about overloading operator<< to print members of a class in the next chapter.

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!

(Okay, to be pedantic, there’s one more minor difference -- structs inherit from other classes publicly and classes inherit privately. We’ll cover what this means in a future chapter, but this particular point is practically irrelevant since you should never rely on the defaults anyway).

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

2a) 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

2b) Add a function named isEqual() to your Point3d class. The following code should run correctly:

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

88 comments to 8.3 — Public vs private access specifiers

  • akde

    Hi Alex,

    Your website is more than awesome. Thanks a lot.

    Can you have a look at my code. The problem is that the array (fA) changes but when I try to print(using myStack.print) it I see it remained unchanged.

    // sandBox.cpp : Defines the entry point for the console application.
    //

    #include    "stdafx.h"
    #include    <iostream>
    #include    <string>
    #include    <array>

    class Stack
    {
    public:
        void reset(Stack stackInp)
        {
            //    Set all values to 0.
            fA.fill(0);
        }

        void print()
        {
            std::cout << "\n";
            
            std::cout << "fA is \n";
            for (int ctr = 0; ctr < 10; ctr++)
            {
                std::cout << fA[ctr] << "\t";
            }
            std::cout << "\n";
        }

        bool push(int inp)
        {
            if (los==10)
            {
                std::cout << "\n stack is full!\n";
                return false;
            }
            else
            {
                //    Dummy array is needed to copy.
                std::array<int, 10> dum{};

                //    Shifting is implemented via copy.
                for (int ctr = 0; ctr < 9; ctr++)
                {
                    dum[ctr + 1] = fA[ctr];
                }
                std::cout << std::endl;

                //    Copy the element (that is pushed) into the first location.
                dum[0] = inp;

                //    copy dum into fA.
                auto fA = dum;

                //    Display fA after push.
                std::cout << "\n After push fA is : ";
                for (int iii = 0; iii < 10; iii++)
                {
                    std::cout << fA[iii];
                }
                //    Increase number of elemets in the stack by 1.
                los++;
                std::cout << "\nNow there are " << los << "Element(s) in the stack\n";
                return true;
            }
        }

    private:
        //    Initialize all values with 0.
        std::array<int, 10> fA{};
        //    At first, there are no elements in the stack.
        int los{ 0 };
    };

    int main()
    {
        Stack    myStack;

        myStack.print();
        myStack.push(2);
        myStack.print();
        return 0;
    }

    • Alex

      The problem here is this line:

      Because you’ve provided a type for fA, the compiler will define a new variable named fA that will shadow the member variable of the same name. Remove the “auto” and it should work.

      Two other thoughts:
      * You don’t need the temporary dum array -- if you copy elements from back to front, you can shift all the elements down one using the same array.
      * Rather than pushing new variables on the front of the array (cause you to have to shift everything down), why don’t you push them on the end, where you can just change the size of the array?

  • Samawia Khan

    What is main use of private class and public class????

  • Kushagra

    This code is not working properly

    #include <iostream>
    class Stack
    {
        int array[10];
        int length;
        
        public:
        void reset()
        {
            length = 0;
            for (int i =0; i< 10; i++)
            {
                array[i] = 0;
            }
        }
        bool push(int x)
        {
                if (length>=10)
            {
                    std::cout << " stack is full";
            return false;
            }
            array[length] = x;
            
            
            
            length++;
            
        
            return true;
        }
        int  pop()
        {
            if (length<0)
            std::cout << " stack is empty ";
            else
            {
                array[length] = 0;
            length-;
            std::cout<<" " << std::endl;
            return array[length-1];
            }
        }
        
            void print()
            {
                if (length >=10)
                std::cout<< " stack is full " <<std::endl;
                else
                {
                
                for (int i = 0; i<(length); i++)
                {
                    std::cout<< array[i]<<" " ;
                }
                std::cout<< std::endl;
                }
            
            
            }
    };
    int main()
    {
        Stack stack;
        stack.reset();

        stack.print();

        stack.push(5);
        stack.push(3);
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.push(8);
        
        stack.print();
        stack.pop();
        stack.print();
        stack.pop();
        stack.print();
        stack.pop();

        stack.print();
        
        return 0;
    }

  • RP

    Hey how memory is allocated to an object when you initiate it?

    • Alex

      It depends. Objects can be allocated on the stack (for local variables), on the heap (dynamically allocated), or in the code or data segments of the executable (for global variables).

  • AMG

    Alex,
    In my opinion, for only one reason "private" should precedes "public", because it’s easier (more intuitive) to understand functions, defined under "public", and, most likely, use private variables. Similar flow is in function definition.

  • Brian M

    Alex,

        I think your tutorials are great but I tend to have some problems with your  quizzes(or the way they are worded) a lot of the times. For an example  on quiz 3) it says to make a private int "to keep track of the length of the stack", yet in the solution you use m_next "to hold the index of the next free element on the stack".

    Also could you explain how this is representing the stack?

    The way I see it is main() is on the bottom of the stack, main() calls(pushes) stack.reset(), then returns(pops) back to main(). Repeat this for the rest of the push/pop/print functions. So for the final function stack.print() the stack would look like this:

    stack.print()
    main()

    Since it is in the middle of the print() function when it prints it would still be on the the stack. To me I don’t understand what the result is suppose to be here. All I see is 5, 3, 8 which is just the numbers that we assigned to different elements of the array. Maybe i’m just looking at this completely wrong.

    Thank you.
    Brian

    • Alex

      It sounds like you’re confusing the call stack (which is used to handle function calls) with the concept of a stack data structure (which can hold a bunch of arbitrary values). This quiz deals with the latter.

      Consider a set of 10 mailboxes, numbered 0 through 9. You can use these like a stack by always sticking mail in the lowest numbered free mailbox, and only taking mail out of the highest numbered full mailbox.

      That’s what the m_next index is doing -- keeping track of which mailbox is the next free one, so we don’t have to iterate over all the mailboxes to figure it out each time. m_next is the length of the current stack.

      I’m not sure how helpful that was. Let me know what I can clarify.

      • Brian M

        Alex

        This was actually very helpful, thank you! You are correct, I was not aware of the concept of the stack data structure, Looking back now I notice I misread lesson 7.9. I remember reading the mailbox analogy but I assumed there was only one stack(the call stack). I see now you also explained a stack data structure. I just thought they were the same thing. Thank you for clearing this up!

        Brian

  • JimD

    Hi Alex,

    I’m not getting why the function definition parameter in quiz question 2d takes the ‘const’ type:

            

    What does that signify, and will that ever take a different type?

    Ace tutorials by the way. 🙂

    Cheers,
    Jim

    • JimD

      Please ignore that question - I’ve got it now. It was a bad idea to skip a few pages to get to the interesting bits. 🙁

    • Alex

      It signifies the parameter is a reference to a const value -- meaning we’re not allowed to change the object being referenced through p. It also helps the caller know that isEqual() won’t change anything.

      It’s not strictly necessary here, since we don’t do anything that necessitates the const, but it’s good practice.

  • Nicolas

    the first time we do reset() and then print() why doesn’t it print 10 zeroes? every element in m_array[10] is 0 so ‘std::cout << m_array[i]’ should print a zero, right?

  • :|

    The other lessons arent working, is there a problem with the website or is from my side?

  • Hamed O.Khaled

    Hey Alex!! I’ve read all questions and the answers.
    there is only 1 thing I confused about what is the difference between compile time and run time or in other words what is the actual reason that make the lines below give error..thanks and sorry for the dumping question.

    • Alex

      Compile time = when compiling your program. Runtime = when running your program.
      Please see http://www.learncpp.com/cpp-tutorial/61-arrays-part-i/ and http://www.learncpp.com/cpp-tutorial/2-9-symbolic-constants-and-the-const-keyword/ for more information on both of these topics.

  • SUNNY

    One more difference between class and object is in during inheritance.
    Struct inherit publicly by default and classes privately.

Leave a Comment

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