Why hide anything
A class does not have to let every part of the program touch its data. Consider a bank account. If the balance is open to everyone, any code can write account.balance = -1000; and break the rules the class was meant to enforce. If the balance is hidden and can only change through a deposit function, that function can check the amount first. Hiding the data and exposing a small set of safe operations is called encapsulation.
C++ controls this with access specifiers, sometimes called access modifiers.
The three specifiers
public:members can be used from anywhere.private:members can be used only by the class's own member functions.protected:members can be used by the class's own member functions and by member functions of classes derived from it. The inheritance lesson comes later; until then, treatprotectedas private with an exception for children.
C++ uses section labels, not a keyword on each member as Java and C# do. A label applies to every member after it, until the next label:
class BankAccount {
private:
double balance = 0; // hidden
public:
void deposit(double amount) {
if (amount < 0) return;
balance += amount;
}
double getBalance() { return balance; }
};
Code outside the class can call deposit and getBalance, but a statement such as account.balance = 100; is rejected at compile time. The check is made by the compiler, so a mistake never reaches a running program.
Defaults: class and struct
If you write no label, the default depends on the keyword you used:
- In a
class, members areprivateby default. - In a
struct, members arepublicby default.
That is the only difference between the two keywords. Programmers usually reach for struct for plain bundles of public data and class for types that protect their state. Writing the labels explicitly, even when they match the default, makes the intent clear.
Getters
When outside code needs to read a private member, the class provides a getter: a public member function that returns the value.
class Dog {
private:
string name;
public:
Dog(string name) { this->name = name; }
string getName() { return name; }
};
With Dog rex("Rex");, the expression rex.name is a compile error, since the member is private. GCC says 'std::string Dog::name' is private within this context. The call rex.getName() works, and it returns a copy of the string, so the caller can read the name but can't change the stored one through it.
Notice that access control is per class, not per object. Inside a Dog member function, you may read the private name of another Dog too, for example other.name in a function that compares two dogs.
The lesson's exercise
The Dog class keeps name in a private: block and has a constructor in the public: block. mainFunction calls rex.getName(), but no such function exists yet. The steps are:
- Under
public:, below the constructor, declare a member function that returns astringand is namedgetName. - Make its body
return name;. This works becausegetNameis a member ofDog, so it may read the private member.
The expected output is:
Dog's name: Rex
The solution in C++
class Dog {
private:
string name;
public:
Dog(string name) { this->name = name; }
string getName() {
return name;
}
};
class Solution {
public:
void mainFunction() {
Dog rex("Rex");
cout << "Dog's name: " << rex.getName() << endl;
}
};
The return type string must match the member's type. A getter declared as void getName() would print or do something, but give back nothing to cout, which would not compile in this line. Also, the constructor must stay public, because mainFunction creates the object.
Common mistakes
- Putting
getNameunderprivate:. The member is then just as unreachable as the data. - Making everything public to avoid the error. It compiles, but it gives up the protection that was the point of the lesson.
- Forgetting that
classdefaults to private when you leave out all the labels, and then wondering why every member is inaccessible. - Forgetting a colon after a label:
publicwithout:is a syntax error. - Ending
getNamewithout areturn. Flowing off the end of a non-void function is undefined behaviour in C++. Most compilers warn about it. - Leaving private data uninitialized. A private
double balance;with no value holds garbage. TheBankAccountabove gives it a starting value with= 0.
Key takeaways
- C++ has
public:,private:andprotected:, written as labels that apply until the next label. - A
classis private by default and astructis public by default. - Keep data private and expose it through member functions, so the class controls how its state changes.
- A getter returns the value of a private member without allowing outside code to assign to it.