C++ Access Specifiers and Encapsulation
Access specifiers decide who may use a class's members:
public: everyone;private: only the class's own methods (and its friends);protected: the class and the classes derived from it (see Inheritance).
Class members are private unless stated otherwise.
Encapsulation
Encapsulation means keeping data private and offering public methods that check and use it. The class can then guarantee its own rules, called invariants: a temperature is never below absolute zero, a balance never negative, a date always valid.
#include <iostream>
class Temperature {
double celsius = 0;
public:
bool setCelsius(double c) {
if (c < -273.15) return false; // impossible: refused
celsius = c;
return true;
}
double getCelsius() const { return celsius; }
double getFahrenheit() const { return celsius * 9 / 5 + 32; }
};
int main() {
Temperature t;
t.setCelsius(25);
if (!t.setCelsius(-500)) std::cout << "Refused -500\n";
std::cout << t.getCelsius() << " C = " << t.getFahrenheit() << " F\n";
return 0;
}Refused -500 25 C = 77 F
Code outside the class cannot write t.celsius = -500;: the compiler stops it with 'celsius' is a private member.
Freedom to change the inside
Because nobody outside depends on the private members, the class can change how it stores its data without breaking any other code. The Temperature class could store Kelvin instead of Celsius, and the users of getCelsius and getFahrenheit would never notice. This is what makes large programs maintainable.
#include <iostream>
#include <string>
#include <vector>
class Playlist {
std::vector<std::string> songs; // could become a linked list later
public:
void add(const std::string& s) { songs.push_back(s); }
std::size_t count() const { return songs.size(); }
const std::string& at(std::size_t i) const { return songs.at(i); }
};
int main() {
Playlist p;
p.add("Song A");
p.add("Song B");
std::cout << p.count() << " songs, first: " << p.at(0) << "\n";
return 0;
}2 songs, first: Song A
Getters and setters wisely
Do not add a getter and a setter for every member by reflex; a setter that accepts anything gives away the protection. Offer methods that match what users need: deposit and withdraw instead of setBalance. Return big members by const& so callers can read without copying.
struct or class?
In C++ the only difference is the default: members of a struct are public until you say otherwise, members of a class are private. By convention, use struct for simple groups of data with no rules, and class when the object protects an invariant.
Practice exercises
- Write a
Dateclass whose setter refuses invalid dates such as 31 February. - Change
Temperatureto store Kelvin internally without changingmain. - Try to read a private member from
mainand read the error message.