Concepts / Classes and Access Control

Classes and Access Control

A class declaration does two jobs at once. It exposes an interface that users may rely on, and it keeps internal parts out of reach. The access modifiers are the mechanism that separates these jobs.

  • Programming

Predicting What Outside Code Can Reach

Suppose you have written a class and want other programmers to use it, but you do not want them to depend on every detail of how it works inside. A class declaration can serve that purpose. It lists what a user is allowed to do with the class and separates that list from the internal parts that make the class work. The running example in this article is a class called Vector, which holds a sequence of double values.

What do you think happens?

A class declaration has a section marked public: and a section marked private:. Which of these can outside code call or use directly?

  • Only the members under public:

  • Only the members under private:

  • Every member, because they all belong to the same class

Reveal answer
Answer:

Only the members under public: are visible to outside code. Members under private: are hidden from users.

Access modifiers set visibility. The keyword public: opens a section whose members are visible to users, and private: opens a section whose members are hidden from them.

Reading the Vector Declaration

Read the declaration below slowly and do not try to memorize it yet. Notice that it contains two kinds of lines. Some describe things a caller can use, and others describe things kept internal to the class. The example is written for illustration and reflects the members named in the source: a constructor Vector(int s), the subscript operator operator[], and the function size() are public, while the data members elem and sz are private.

cpp
Notes on the code
  • class Vector opens the declaration of the whole class
  • public: opens the interface section, visible to users
  • Vector(int s) is the constructor, a function member users can call to create an object
  • operator[] is a function member that lets users access elements by index
  • size() is a function member that reports the number of elements
  • private: opens the hidden section, not reachable from outside
  • elem and sz are data members that store the information the class needs
class Vectorpublic: interfaceVector(int s)constructorprivate: hiddenoperator[]subscriptsize()function memberelemdata memberszdata membercontainscontains
Which members of the Vector declaration can a user see and call from outside, and which are hidden inside the class boundary?

Data Members and Function Members

The parts that belong to a class are called class members. The Vector declaration contains two kinds. Data members store information, and in this declaration they are elem and sz. Function members perform operations, and here they are the constructor Vector(int s), the subscript operator operator[], and the function size().

  • Data members: elem and sz, which store the information the class keeps
  • Function members: Vector(int s), operator[], and size(), which perform operations on the class
  • Access modifiers decide which of these members a user can reach from outside

How Access Modifiers Set Visibility

Access modifiers are keywords that control which members can be reached from outside the class. Their job is to set visibility. The keyword public: opens a section whose members are visible to users, and private: opens a section whose members are hidden from them. These two keywords are the only access modifiers this declaration needs, and they are how the declaration decides which of its two jobs each member performs.

Key point

A class declaration does two jobs at once. It exposes an interface that users may rely on, and it keeps internal parts out of reach. The access modifiers are the mechanism that separates these jobs.

Tracing a User of Vector

Now follow a user who wants to work with a Vector. The user does not open the class's internals. Instead, the user includes the header, creates an object, and uses only the public members. The code below is written for illustration and is not part of the source.

cpp
Notes on the code
  • The include line gives the user access to the declaration in Vector.h
  • Creating v calls the public constructor
  • Indexing with operator[] uses a name found in the public section
  • size() is also public, so the call is part of the interface
  • The commented line names elem, a private member, which is outside the interface

Notice where the program depends on the declaration. Every line that compiles against Vector uses names found in the public section. The user code never names the private members, which is exactly the separation the header is designed to create.

Watching a Call Move From Allowed to Rejected

Compare two lines that both refer to a Vector object named v. The first line names a member from the public section. The second names a member from the private section. Only the state of the name changes between them, and that change decides whether the line is part of the interface.

Before
int n = v.size();

The name size is in the public section, so the call uses the declared interface.

After
int n = v.sz;

The name sz is in the private section, so the access falls outside the declared interface.

The Header File as the Carrier of the Interface

Definition

A header file such as Vector.h holds the declarations that specify a module's interface, and users include it to reach that interface.

Two ideas in that definition deserve attention. First, a header file holds declarations, which describe what exists and how it is used. It does not hold the full working details of the class. Second, the file is shared. A user does not copy the declaration into their own code. They include the file, so the same declaration is available to every program that needs the module.

user source file#include Vector.hVector.hheader with the declarationpublic interfaceconstructor, operator[],size()user programuses only public namescontainsbrings indeclaresused by
How does a user's source file get access to the interface, and how does the header carry the declaration?

Why the Interface File Takes Its Name

The declarations that specify the interface to a module are usually placed in a file whose name indicates its intended use. For the Vector class, that file is named Vector.h. The name tells a reader what the file is for before they open it. A reader who wants to know how to use Vector can look for Vector.h, and a reader who sees the name can expect a declaration rather than a full implementation.

Locating Where Misuse Diverges From the Interface

When a program misbehaves at the boundary with a class, the fault is usually found at the point where user code accesses the interface. The declaration defines what that access may legally name. A call that uses a name from the public section stays on the declared path. A call that names a private member leaves that path at the moment of access.

user writes v.namename in publicsection?uses declaredinterfaceaccess rejected hereyesno
At which step does a call that does not match the declared interface get rejected, and what happens before and after that point?

Mistakes Beginners Make With Class Boundaries

  • Common mistake

    Treating every member of a class as usable from outside

    What it looks like
    Writing v.elem[0] = 1.0; in user code
    Why it fails

    elem sits under private:, so it is hidden from users and is not part of the interface.

    Do this instead

    Use the public members such as operator[] to access elements.

  • Common mistake

    Copying the declaration into each source file

    Why it fails

    The header is meant to be shared. Copying it means each program holds its own version of the interface.

    Do this instead

    Include Vector.h so every program that needs the module uses the same declaration.

  • Common mistake

    Expecting the header to hold the full working details of the class

    Why it fails

    A header file holds declarations, which describe what exists and how it is used.

    Do this instead

    Read Vector.h for the interface, and treat the internal parts as separate from what users depend on.

Practice Sorting Members by Visibility

EASY

Given a class with a public: section containing a constructor and size(), and a private: section containing a data member named count, decide which of these user lines would stay on the declared interface: (a) v.size(), (b) v.count, (c) a call to the constructor when creating an object. Explain your choice for each.

Hints
  • Ask which section each name sits in.
  • Names under public: are part of the interface; names under private: are not.
  • Creating an object uses the constructor, which is a public member here.

Key Takeaways

  • A class declaration contains interface members under public: and internal members under private:, and access modifiers control which members outside code may reach.
  • The interface declaration for Vector is placed in Vector.h, a file named for its purpose, so readers know what it is for before opening it.
  • A header file holds declarations, and users reach the interface by including it rather than copying the declaration.
  • When a program misbehaves at a class boundary, look at the access point, because the declaration defines which names that access may legally use.

Related concepts

More concepts starting with C