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.
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?
Reveal 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.
- 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
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[], andsize(), 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.
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.
- 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.
int n = v.size();The name size is in the public section, so the call uses the declared interface.
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
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.
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.
Mistakes Beginners Make With Class Boundaries
Common mistake Treating every member of a class as usable from outside
What it looks likeWriting v.elem[0] = 1.0; in user codeWhy it failselem sits under private:, so it is hidden from users and is not part of the interface.
Do this insteadUse the public members such as operator[] to access elements.
Common mistake Copying the declaration into each source file
Why it failsThe header is meant to be shared. Copying it means each program holds its own version of the interface.
Do this insteadInclude 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 failsA header file holds declarations, which describe what exists and how it is used.
Do this insteadRead Vector.h for the interface, and treat the internal parts as separate from what users depend on.
Practice Sorting Members by Visibility
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.