Shiklo Tools
PDF40
Image20
Calculators & Converters25
Text & Writing13
Developer26
Video14
Audio14
Document14
Data & Spreadsheet12
Web & SEO9
OCR & Scanning5
Archive & File12
Security & Privacy23
Health & Medical29
QR & Barcode5

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;
}
Output
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;
}
Output
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

  1. Write a Date class whose setter refuses invalid dates such as 31 February.
  2. Change Temperature to store Kelvin internally without changing main.
  3. Try to read a private member from main and read the error message.