ScAs: C14 Explained for Beginners
Let’s go through Chapter 14 (More skills for Object-Oriented Programming) like you’re a true beginner, with why you should / shouldn’t do things, and lots of concrete examples.
What Chapter 14 is trying to teach you
You already know classes/objects. This chapter gives you “extra powers” that make classes feel natural to use in real programs:
Static members (stuff that belongs to the class, not each object)
Friend functions (carefully allowing an outside function to access private data)
Operator overloading (making
+,==,<<, etc. work on your objects)Modules (C++20) (a newer way to organize code instead of lots of headers)
1) Static members (class-wide data & functions)
The idea
Normally, every object gets its own copy of member variables.
class Dog {
public:
int age;
};
If you make two dogs:
dog1.ageanddog2.ageare two separate ages.
But sometimes you want one shared piece of information for the whole class.
Example: “How many Dog objects exist?”
That’s what static data members are for.
1A) Static data member (shared variable)
Example: counting how many objects were made
class Dog {
private:
static int count; // shared by ALL Dog objects
public:
Dog() { count++; }
static int get_count() { return count; }
};
// Define it once (outside the class)
int Dog::count = 0;
Use it:
Dog a;
Dog b;
cout << Dog::get_count(); // prints 2
Why you should do this
Static is perfect when the data is about the class as a whole, like:
number of objects created
a shared tax rate
a shared “next ID” counter
Why you should NOT do this
Don’t use static for data that should be different per object:
price,name,age,gallons, etc.
If price were static, changing one product’s price changes all products, which is almost always wrong.
1B) Static member function (class-wide function)
Key beginner rule:
A static function does not belong to any one object.
So it cannot use normal (non-static) members like this->name because there is no “this object”.
Example:
class Dog {
public:
string name; // non-static
static void print_name() {
// cout << name; // ERROR: which dog's name?
}
};
What static functions are good for
helper/utility functions
counting objects
validation functions
input helper class (like a
Console::get_int(...)idea)
Why an input helper is often static
Because you don’t need a Console object holding data like “consoleName” — you just want tools.
So this makes sense:
int x = Console::get_int("Enter age: ");
Creating a Console object like Console c; is pointless unless the object stores meaningful state.
2) Friend functions (letting one outside function access private stuff)
The problem friend functions solve
Normally, private means:
Only the class’s own member functions can access it.
Example:
class BankAccount {
private:
double balance;
public:
BankAccount(double b) : balance(b) {}
};
Outside the class:
BankAccount a(100);
cout << a.balance; // not allowed (private)
That’s good! It prevents random code from messing with your object.
2A) What is a friend function?
A friend function is a function that is not a member of the class, but the class gives it permission to access private things.
class BankAccount {
private:
double balance;
public:
BankAccount(double b) : balance(b) {}
friend void steal_money(BankAccount& acc);
};
void steal_money(BankAccount& acc) {
acc.balance = 0; // allowed because it's a friend
}
Why you might use friend functions
Sometimes you have an operation that:
feels like it doesn’t “belong” to either object
needs access to private data of two different classes
commonly happens with stream operators like
<<
Example idea: pour(tank, can) where both need private access.
2B) Why you usually should NOT use friend
Because it breaks encapsulation.
Friend is like saying:
“Okay, you can bypass my safety rules.”
That makes code harder to reason about and easier to break later.
Better alternative (often)
Use public methods that do the job safely:
class BankAccount {
private:
double balance;
public:
void withdraw(double amt) {
if (amt <= balance) balance -= amt;
}
double get_balance() const { return balance; }
};
This keeps your rules inside the class.
Use friend when it genuinely makes design cleaner, not because it’s convenient.
3) Operator overloading (making operators work with objects)
The point
You want this to be possible:
Money m1(5.00);
Money m2(2.50);
Money m3 = m1 + m2;
But C++ doesn’t know what + means for your class unless you define it.
That’s operator overloading:
“When you see
a + bandaandbare Money objects, call my code.”
3A) Overloading + and - (binary operators)
Correct beginner behavior
a + b should NOT change a or b.
It should create and return a new result.
class Money {
private:
int cents;
public:
Money(int c) : cents(c) {}
Money operator+(const Money& other) const {
return Money(this->cents + other.cents);
}
};
Why const at the end?
Because adding money should not change the money objects.
Why const Money& other?
&avoids copying (faster)constpromises you won’t modifyother
Why you should NOT mutate inputs in +
If + changed the left object, this becomes confusing:
Money a(100), b(50);
Money c = a + b;
// if a changed, that's surprising and dangerous
If you want mutation, use += instead.
3B) Overloading ++ (unary operator): prefix vs postfix
Prefix: ++x
changes x
returns the changed x
Postfix: x++
returns the old value
then changes x
That difference matters.
Prefix overload
Money& operator++() {
cents++;
return *this; // returns the same object (by reference)
}
Postfix overload (has a dummy int)
Money operator++(int) {
Money old = *this; // copy old value
cents++;
return old; // return the copy (old)
}
Why postfix needs the “dummy int”
It’s just a marker so C++ can tell postfix and prefix apart.
Why prefix is usually preferred
Postfix often requires a copy (like old = *this) → extra work.
3C) Relational operators: ==, <, >
These should return bool.
Example:
bool operator==(const Money& other) const {
return cents == other.cents;
}
Why you should do relational overloads
It lets your objects behave naturally:
if (m1 < m2) ...
if (m1 == m2) ...
Why you should NOT do weird meanings
Don’t make < mean something unexpected. Keep it intuitive, or future-you will suffer.
3D) Stream operators: << and >> (printing and reading)
You want:
cout << m1;
cin >> m1;
These are usually non-member functions because the left side is cout (an ostream), not your object.
Typical pattern:
class Money {
private:
int cents;
public:
Money(int c = 0) : cents(c) {}
friend ostream& operator<<(ostream& out, const Money& m);
};
ostream& operator<<(ostream& out, const Money& m) {
out << "$" << (m.cents / 100.0);
return out; // IMPORTANT
}
Why you MUST return ostream&
So chaining works:
cout << "Money: " << m1 << "\n";
If you don’t return the stream, chaining breaks.
4) Modules (C++20) — modern file organization
The problem with old headers (.h)
Headers often cause:
huge compile times
accidental redefinitions / include-order issues
“leaking” implementation details
tons of
#includeclutter
Modules idea
Instead of:
#include "money.h"
You do:
import money;
And inside the module you control what is public using export.
4A) Exporting functions/classes
Example concept:
export module money;
export class Money {
...
};
Now other files can:
import money;
Money m;
Why modules are nice
cleaner boundaries (only exported things are public)
fewer include-guard problems
often faster builds (depends on compiler support)
Why you might NOT use modules yet
your course/compiler setup might not support modules well
build systems might be configured for traditional headers
So: learn them, but expect to still see headers in many classes/projects.
The “if you master only these, you’re solid” list
If you can confidently explain these, you’ve mastered the chapter:
Static data member = one shared variable for the whole class
Static function = no “this object”, so it can’t use non-static members
Friend function = outside function that can access private (use sparingly)
+should return a new object and not mutate operandsPrefix
++xvs postfixx++and why postfix uses a dummyint<<returnsostream&to allow chainingModules use
exportandimportto control visibility and organization