Classes, structs and access control
A class bundles data (member variables) with the functions that work on it (member functions). The point is not just grouping: a class can protect its data so that it is only changed through functions that keep it valid. An Account balance should only change through deposit and withdraw, which can refuse bad amounts. That guarantee is called an invariant, and protecting it is called encapsulation.
Access specifiers say who may use a member. public members are usable by anyone; private members only by the class's own member functions (and friends); protected matters for inheritance (Module 08). The only difference between struct and class in C++ is the default: a struct's members are public until you say otherwise, a class's are private. The convention: struct for plain data with no invariant (a Point, a config record), class when there is something to protect.
#include <iostream>
#include <string>
struct Point { // plain data: members public by default
int x = 0;
int y = 0;
};
class Account { // members private by default
public:
void deposit(int amount) {
if (amount > 0) balance_ += amount; // the class enforces its rule
}
bool withdraw(int amount) {
if (amount <= 0 || amount > balance_) return false;
balance_ -= amount;
return true;
}
int balance() const { return balance_; } // read access only
private:
int balance_ = 0; // default member initializer
};
int main() {
Point p{3, 4};
p.x = 10; // fine: public data
std::cout << p.x << ',' << p.y << '\n';
Account acc;
acc.deposit(500);
acc.deposit(-200); // ignored
std::cout << std::boolalpha << acc.withdraw(800) << ' ' << acc.withdraw(300) << '\n';
std::cout << "balance " << acc.balance() << '\n';
}10,4
false true
balance 200Add a transferTo(Account& other, int amount) member function that only moves money if the withdrawal succeeds. Note that it may read other.balance_ directly: private is per class, not per object.
'balance_' is a private member of 'Account'
#include <iostream>
class Account {
public:
void deposit(int amount) { if (amount > 0) balance_ += amount; }
int balance() const { return balance_; }
private:
int balance_ = 0;
};
int main() {
Account acc;
acc.balance_ = 1'000'000;
std::cout << acc.balance() << '\n';
}main.cpp:13:9: error: 'balance_' is a private member of 'Account'
13 | acc.balance_ = 1'000'000;
| ^
main.cpp:8:9: note: declared private here
8 | int balance_ = 0;
| ^Code outside the class cannot touch private members. This is the compiler enforcing the class's promise that the balance only changes through deposit and withdraw. The trailing underscore in balance_ is just a common naming convention for data members.
Go through the public interface. If outside code genuinely needs to set a value, add a member function that validates it, rather than making the field public.
acc.deposit(1'000'000);