Unit 8: More Tools
Overloading, memory and mistakes.
Unit 8 of 8 in C++ for kids. Its 5 lessons are One Name, Several Functions, Asking for Memory, When Things Go Wrong, Handy Library Tools and Toolkit Master — below is everything each one explains, and a question or two from it to try.
Every sample on this page was compiled and run with g++ before it shipped, and prints exactly what it says it prints.
This unit opens with a fortnight’s trial of everything — no card needed — or with a family plan, bought in the iPhone app. The first two units of every track are free for ever. Try it in the app.
🎭 One Name, Several Functions
The same name for the same idea
Overloading lets several functions share a name as long as they take different values. C++ picks whichever matches the call.
C++
#include <iostream>
using namespace std;
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int main() {
cout << add(1, 2) << endl;
cout << add(1.5, 2.5) << endl;
return 0;
}
It prints
3 4
Or a different number of them
Taking two values or three is enough to tell them apart.
C++
#include <iostream>
using namespace std;
int total(int a, int b) { return a + b; }
int total(int a, int b, int c) { return a + b + c; }
int main() {
cout << total(1, 2) << endl;
cout << total(1, 2, 3) << endl;
return 0;
}
It prints
3 6
Why C never had this
In C, one name means exactly one function, so C programmers write absInt and absDouble. Overloading is one of the first real conveniences C++ added.
C++
#include <iostream>
#include <string>
using namespace std;
void show(int n) { cout << "number " << n << endl; }
void show(string s) { cout << "text " << s << endl; }
int main() {
show(42);
show("hello");
return 0;
}
It prints
number 42 text hello
Try it yourself
What may NOT be the only difference between two overloads?
- How many values they take
- The types they take
- What they return
- The order of their types
Answer it in the app
🧱 Asking for Memory
new asks, delete gives back
C++ uses new to ask for space while the program is running, and delete to hand it back. Every new needs exactly one delete.
C++
#include <iostream>
using namespace std;
int main() {
int *n = new int;
*n = 42;
cout << *n << endl;
delete n;
return 0;
}
It prints
42
A whole block of them
new int[3] asks for three in a row, and the matching delete[] needs the brackets too.
C++
#include <iostream>
using namespace std;
int main() {
int *nums = new int[3];
for (int i = 0; i < 3; i++) {
nums[i] = i * 10;
}
cout << nums[0] << " " << nums[2] << endl;
delete[] nums;
return 0;
}
It prints
0 20
Objects too — and the constructor still runs
new Dog("Rex") builds an object on the heap and hands you a pointer, so you reach its members with ->.
C++
#include <iostream>
#include <string>
using namespace std;
class Dog {
public:
string name;
Dog(string n) { name = n; }
void speak() { cout << name << " says woof" << endl; }
};
int main() {
Dog *d = new Dog("Rex");
d->speak();
cout << d->name << endl;
delete d;
return 0;
}
It prints
Rex says woof Rex
Try it yourself
What happens if you use a pointer after deleting it?
- C++ stops you
- It points at memory that is no longer yours — one of the nastiest bugs there is
- It becomes 0
- Nothing at all
Answer it in the app
🚨 When Things Go Wrong
Throwing a problem to whoever can handle it
throw stops what you are doing and hands the problem outwards. try marks the risky part and catch deals with it.
C++
#include <iostream>
using namespace std;
int main() {
try {
throw 42;
} catch (int code) {
cout << "caught " << code << endl;
}
return 0;
}
It prints
caught 42
It travels out of functions
A throw does not have to be caught where it happened — it keeps going outwards until something catches it. That is what makes it useful deep inside a program.
C++
#include <iostream>
#include <string>
using namespace std;
int divide(int a, int b) {
if (b == 0) {
throw string("cannot divide by zero");
}
return a / b;
}
int main() {
cout << divide(10, 2) << endl;
try {
cout << divide(1, 0) << endl;
} catch (string problem) {
cout << "caught: " << problem << endl;
}
return 0;
}
It prints
5 caught: cannot divide by zero
Nothing thrown, nothing caught
When the try block finishes normally, the catch is skipped entirely.
C++
#include <iostream>
using namespace std;
int main() {
try {
cout << "all fine" << endl;
} catch (int e) {
cout << "never runs" << endl;
}
cout << "carrying on" << endl;
return 0;
}
It prints
all fine carrying on
Try it yourself
Why throw rather than just print a warning?
- It looks better
- Printing lets the program carry on with nonsense; throwing stops it before damage is done
- It is faster
- There is no difference
Answer it in the app
🧰 Handy Library Tools
Reading a whole line
cin >> name stops at the first space, so a full name never arrives. getline reads the whole line, spaces and all.
C++
#include <iostream>
#include <string>
using namespace std;
int main() {
string line;
getline(cin, line);
cout << "Hello, " << line << "!" << endl;
return 0;
}
It prints
Hello, Ada Lovelace!
Sorting a vector
sort from <algorithm> puts a vector in order. v.begin() and v.end() say where to start and stop.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> scores = {5, 2, 9, 1};
sort(scores.begin(), scores.end());
for (int s : scores) {
cout << s << " ";
}
cout << endl;
return 0;
}
It prints
1 2 5 9
Try it yourself
Why use getline rather than cin >> for a full name?
- It is faster
- `cin >>` stops at the first space, so only the first word arrives
- getline is newer
- They are the same
Answer it in the app
🏆 Toolkit Master
Try it yourself
What does this print?
C++
#include <iostream>
using namespace std;
int f(int n) { return n * 2; }
double f(double n) { return n * 2; }
int main() {
cout << f(3) << endl;
cout << f(2.5) << endl;
return 0;
}
Answer it in the app