optional · CSS study notes
10. Protected Members
protectedmembers are accessible within the defining class and any class derived from it, but not from outside code (unlikepublic) and not from unrelated classes (unlike... well, nothing else grants this specific visibility)- Sits between
private(class-only) andpublic(everyone) — the natural choice for data a base class wants to expose to its subclasses only
class Person
{
protected:
string name; // accessible to Person AND any derived class, not from main()
public:
Person(string n) : name(n) {}
};
class Student : public Person
{
public:
Student(string n) : Person(n) {}
void show() { cout << name; } // OK -- name is protected, Student can access it
};
// int main() { Student s("Ali"); cout << s.name; } --> ERROR: name is protected, not accessible outside
The three access levels, side by side
class Base
{
private: int a; // Base only
protected: int b; // Base + derived classes
public: int c; // everyone
};
class Derived : public Base
{
public:
void test()
{
// a = 1; // ERROR -- private, not accessible even in derived class
b = 2; // OK -- protected is accessible in derived classes
c = 3; // OK -- public is always accessible
}
};
int main()
{
Derived d;
// d.a; // ERROR
// d.b; // ERROR -- protected not accessible from OUTSIDE the class hierarchy either
d.c; // OK -- public
}
The rule, stated precisely
protected is accessible from: (1) the class that declares it, and (2) any class that derives from it — but not from ordinary outside code, even code that has an object of the derived class. This is the detail students most often get wrong: protected is not "public within the family and private outside" — it's still fully blocked from any code outside the class hierarchy.
Real-world use case
class Employee
{
protected:
double baseSalary; // subclasses need this to calculate their own pay, outside code doesn't
public:
Employee(double s) : baseSalary(s) {}
};
class Manager : public Employee
{
private:
double bonus;
public:
Manager(double s, double b) : Employee(s), bonus(b) {}
double totalPay() { return baseSalary + bonus; } // uses protected base data directly
};
Important MCQs
- A
protectedmember is accessible from:- a) Anywhere in the program b) The defining class and any class derived from it, but not from outside code c) Only from main() d) Nowhere, ever
- If
main()creates aStudentobject (derived fromPerson, wherenameis protected), canmain()directly accesss.name?- a) Yes, always b) No — protected is not accessible from ordinary outside code, even via a derived object c) Only if Student is a friend d) Only if name is also public
protectedsits, in terms of visibility, between:- a) public and static b) private and public c) friend and static d) const and private
✅ Self-Test Questions (with Answers)
Q1. Can outside code (e.g., main()) access a protected member through a derived-class object? Why or why not?
Ans: No. From the point of view of any code outside the class hierarchy, protected behaves exactly like private — it is completely inaccessible. protected grants access to code inside the defining class and its descendants, not to objects of those classes viewed from outside. So main() holding a Student object still cannot write s.name; the member is visible only within the bodies of member functions of Person, Student, and any further derived class.
class Person {
protected:
string name;
public:
Person(string n) : name(n) {}
};
class Student : public Person {
public:
Student(string n) : Person(n) {}
void show() const { cout << name << '\n'; } // OK: INSIDE a derived member function
};
int main() {
Student s("Ali");
s.show(); // OK -- goes through the public interface
// cout << s.name; // ERROR: 'std::string Person::name' is protected within this context
}
The precise rule to state in an exam: access is decided by where the code is written, not by which object it is applied to. Outside code sees only the public interface, so protected and private are indistinguishable from there.
A subtle extra rule examiners occasionally probe: a derived class may access a protected base member only through an object of its own type (or a further-derived type), not through a plain base object or a sibling class:
class Student2 : public Person {
public:
void f(Person& p, Student2& s) {
// cout << p.name; // ERROR: cannot reach it through a bare Person
cout << s.name; // OK -- through its own type
}
};
Summary line: private = the declaring class (plus friends) only; protected = the declaring class and all descendants; public = everywhere. Protected is not "public within the family and private outside" in the loose sense — it is strictly blocked from all code outside the hierarchy.
Q2. Why is protected a better choice than private for baseSalary in the Employee/Manager example?
Ans: Because Manager::totalPay() needs to read baseSalary directly, and a private base member is inaccessible to derived classes — the line return baseSalary + bonus; would simply not compile. Declaring it protected gives every subclass direct access while still blocking all outside code, which is exactly the visibility the design calls for: subclasses must extend the pay calculation, but main() must never touch the salary.
class Employee {
protected:
double baseSalary; // private here would break Manager
public:
Employee(double s) : baseSalary(s) {}
};
class Manager : public Employee {
double bonus;
public:
Manager(double s, double b) : Employee(s), bonus(b) {}
double totalPay() const { return baseSalary + bonus; } // OK: protected
};
int main() {
Manager m(50000, 10000);
cout << m.totalPay(); // 60000
// cout << m.baseSalary; // ERROR: 'baseSalary' is protected within this context
}
The honest caveat — worth a mark in a good answer: protected is convenient, not automatically better. It weakens encapsulation, because the member becomes part of the contract with every present and future subclass: once several classes read and write baseSalary directly, you can no longer change how it is stored, and no subclass is forced to respect any invariant. The safer design keeps the data private and exposes a protected accessor, so the base class retains control of every read and write:
class Employee2 {
double baseSalary; // PRIVATE data
protected:
double getBaseSalary() const { return baseSalary; } // protected FUNCTION
void setBaseSalary(double s) { if (s >= 0) baseSalary = s; }
public:
Employee2(double s) : baseSalary(s >= 0 ? s : 0) {}
};
Rule to quote: "protected member functions, private data." Use protected data when the exam question explicitly demands it (FPSC 2026 Q4(c) does) or when a tight, closed hierarchy makes the convenience worth the coupling.
Q3. What's the practical difference between making baseSalary protected vs public?
Ans: protected confines direct access to the inheritance family — Employee and every class derived from it; public throws it open to the entire program, so any function anywhere can read and overwrite it without validation. In practice the difference is who can corrupt the value and how much code you must audit when it goes wrong.
| Aspect | protected baseSalary | public baseSalary |
|---|---|---|
| Who can access it | Employee and its subclasses only | Any code in the program |
| Access from main() | Compile error | Allowed |
| Can be set to an invalid value? | Only by a subclass | By anyone, anywhere |
| Encapsulation | Partially preserved | Destroyed |
| Freedom to change representation later | Limited to subclasses | None — breaks unknown callers |
| Code to audit when the value is wrong | The class hierarchy | The whole program |
class Employee {
protected:
double baseSalary; // family-only
public:
Employee(double s) : baseSalary(s) {}
void raise(double pct) { // controlled, validated mutation
if (pct > 0 && pct <= 50) baseSalary *= (1 + pct / 100);
}
double getBaseSalary() const { return baseSalary; }
};
class Manager : public Employee {
double bonus;
public:
Manager(double s, double b) : Employee(s), bonus(b) {}
double totalPay() const { return baseSalary + bonus; } // OK: protected
};
int main() {
Manager m(50000, 10000);
// m.baseSalary = -1; // ERROR with 'protected' -- the bug is caught at compile time
// With 'public', that same line would COMPILE and silently corrupt the payroll.
m.raise(10); // the sanctioned route, with validation
}
The deeper point: a public data member becomes part of the class's permanent contract — you can never change how the salary is stored (say, to an integer number of rupees, or to a computed value from grade and steps) without breaking unknown client code. protected limits that exposure to subclasses; private plus accessors eliminates it entirely. Hence the standard guidance: "protected member functions, private data."
📌 Sample & Repeated FPSC Questions (2016–2026)
2026, Paper I, Q4(c) (8 marks) — Demonstrate method overriding using a base class Account and a derived class Current Account. Make balance a protected data member.
class Account
{
protected:
double balance;
public:
Account(double b) : balance(b) {}
virtual void withdraw(double amount)
{
if (amount <= balance) { balance -= amount; }
else cout << "Insufficient funds.\n";
}
};
class CurrentAccount : public Account
{
double overdraftLimit;
public:
CurrentAccount(double b, double od) : Account(b), overdraftLimit(od) {}
void withdraw(double amount) override // overriding
{
if (amount <= balance + overdraftLimit) balance -= amount; // uses inherited protected member
else cout << "Exceeds overdraft limit.\n";
}
};
Key reasoning points:
balanceis declaredprotectedinAccountspecifically soCurrentAccountcan access and modify it directly, without a getter/setter.- Had
balancebeenprivate, this exact code would not compile insideCurrentAccount::withdraw(). withdraw()must bevirtualfor a call through anAccount*pointing at aCurrentAccountobject to dispatch to the overridden version.
2018, Paper I, Q4(a) (5 marks) — Consider a hierarchy where A is the base class, B and C derive from A, and D and E derive from C. In which class(es) would it make most sense to have protected members? Which class(es) would be able to access those protected members directly?
Protected members belong in base classes meant to be extended but which should hide internals from the outside world — here that's class A (root, extended by B and C) and class C (itself extended by D and E).
- Protected members in A → directly accessible by A, B, C, D, and E (all descendants, direct or transitive).
- Protected members in C → directly accessible by C, D, and E only (NOT A or B — they aren't descendants of C).
2018, Paper I, Q4(b) (5 marks) — Which class(es) can access private members of class C directly?
Only C itself. Private members are never directly accessible to any derived class — not even D and E, which derive straight from C. D/E can only reach C's private data indirectly, through C's own public/protected getters/setters, unless C explicitly names a friend.
Exam angle: Q4(a) and Q4(b) are a matched pair — examiners test whether you conflate "protected" (visible to the whole derived family) with "private" (visible to the declaring class only, no exceptions without friend).
2025, Paper I, Q7 (1 mark, MCQ) — Which programming language uses the concept of friend function?
- A) Python
- B) Java
- C) C#
- D) None of these
Correct answer: D. friend functions/classes — letting a non-member function access private/protected members — are a C++-specific mechanism; Python, Java, and C# have no equivalent.
📜 Past-Paper Questions & MCQs (CSS 2016–2026)
2018 · Paper-I · Q4(a) · 5 marks
Q. In the hierarchy A → B, A → C, C → D, C → E, in which class(es) does it make most sense to have protected members, and which classes can access them directly?
Ans.
- Protected members make sense in the base classes that have derived classes: A and C.
- Protected members of A are directly accessible in A, B, C, D and E (all descendants).
- Protected members of C are directly accessible in C, D and E only, not in A or B.
- B, D and E have no children, so protected members there add nothing over private.
2018 · Paper-I · Q4(b) · 5 marks
Q. Which class(es) can access private members of class C directly?
Ans.
- Only class C itself (its own member functions) and its friend functions or classes.
- Not A, B, D or E. Derived classes D and E must use public or protected members of C instead.