Theory
Anyone could open the drawer
Version 1 of the CanteenTill class kept the day's cash in a plain variable. Any code, anywhere, could write:
till.cash = 0;
One intern's buggy loop did exactly that at 4 pm. No error, no warning, Rs 18,000 of records gone.
The fix is not "be careful". The fix is a language feature that makes the compiler refuse such a line. C++ gives you three locks: public, private, protected.
Theory
Counter, kitchen, cash drawer
Walk into the canteen:
- The counter is public: anyone can stand there and place an order.
- The kitchen is protected: staff and the family's franchise branches may enter, customers may not.
- The cash drawer is private: only the owner opens it, staff included stay out.
Every member of a class lives in one of these three zones, and the compiler is the guard who never sleeps.
Theory
The three specifiers, formally
An access specifier sets who may use the members declared after it:
- public: accessible from anywhere the object is visible, including
main(). - private: accessible only inside the class's own member functions. Nobody outside, not even a derived class.
- protected: like private to the outside world, but derived classes may access it (this matters in inheritance, two lessons ahead).
A specifier applies to every member after it until the next specifier appears.
Practical
The drawer, locked properly
#include <iostream>
using namespace std;
class CanteenTill {
private:
double cash; // the drawer: owner only
protected:
double costPrice; // the kitchen: this class + child classes
public:
int ordersToday; // the counter: anyone
void addSale(double amount) { // public gate to the private drawer
cash = cash + amount;
}
double report() { return cash; }
};
int main() {
CanteenTill till;
till.ordersToday = 1; // ok: public
till.addSale(30.0); // ok: public function touches private cash
// till.cash = 0; // ERROR: 'cash' is private
return 0;
}
At a glance
Who can access what
| Accessed from | public | protected | private |
|---|---|---|---|
| Same class's functions | yes | yes | yes |
| Derived class's functions | yes | yes | no |
| Outside (main, other code) | yes | no | no |
Think first
Predict the compiler
Using the class above, main() runs:
cout << till.cash;
Before tapping: compile error or output? And if it is an error, what is the one-line fix that keeps cash private?
Show the answer
Compile error: something like 'cash' is private within this context. The fix is to go through the public gate the class already offers: cout << till.report();. That is the whole pattern of encapsulation: private data, public functions that mediate access. The drawer stays shut; the counter answers questions about it.
Quiz
A member is declared with NO specifier at the top of `class CanteenTill { double cash; ... }`. Who can access cash?
- Only the class's own member functions: class members are private by default
- Everyone: members are public by default
- The class and its children: members are protected by default
- Nobody at all until a specifier is written
Show the answer
Only the class's own member functions: class members are private by default
In a class, everything before the first specifier is private. The famous twin fact: in a struct, the default is public. That class-vs-struct default is a beloved 2-mark question. Option B describes struct behaviour, option C's default does not exist in C++, and option D is imaginary: members always get some access level.
Watch out
The default trap
Exams love: "What is the difference between class and struct in C++?" The expected answer is exactly one line: class members are private by default, struct members are public by default. Everything else about them is the same.
Second trap: protected looks useless until inheritance arrives. Do not call it "same as private" in an answer: to a derived class they behave differently, and that difference is the point.
Theory
This is encapsulation's muscle
The next lessons name the concept: data hiding and encapsulation. Notice that they are only possible because these specifiers exist: without private, "hiding" would be a polite request instead of a compiler-enforced rule. When you later write getters and setters at a job interview, you are applying this exact table.
Summary
Key takeaways
- public: accessible anywhere; private: only the class's own functions; protected: the class plus derived classes.
- A specifier governs all members after it until the next one.
- Class default is private; struct default is public (classic 2-marker).
- Outside code touches private data only through public member functions (getters/setters).
- protected earns its keep in inheritance: children can use it, outsiders cannot.
- Memory hook: counter, kitchen, cash drawer.