Define, overload, and call functions. Pass by value versus reference, default arguments, lambdas (anonymous functions), and operator overloading.
Several functions can share a name as long as their parameter lists differ — the compiler picks the match (static polymorphism). Default arguments let callers omit trailing parameters.
#include <iostream>
#include <string>
int area(int side) { return side * side; } // square
int area(int w, int h) { return w * h; } // rectangle — overload
void greet(const std::string& name,
const std::string& greeting = "Hello") { // default argument
std::cout << greeting << ", " << name << "!\n";
}
int main() {
std::cout << area(4) << " " << area(3, 5) << "\n"; // 16 15
greet("Ada"); // Hello, Ada!
greet("Ada", "Hi"); // Hi, Ada!
return 0;
}By value copies the argument — cheap for ints, wasteful for big objects. A reference (&) is an alias to the caller’s object: use plain & to modify it, const& to read a large object without copying. This choice is one of the most important habits in C++.
#include <iostream>
#include <string>
void addTax(double& price) { price *= 1.2; } // modifies caller
double lengthOf(const std::string& s) { return s.size(); } // read, no copy
int main() {
double p = 100.0;
addTax(p); // p is now 120
std::cout << p << "\n";
std::string title = "Effective C++";
std::cout << lengthOf(title) << "\n"; // 14, and no string was copied
return 0;
}A lambda is an anonymous function you can define where you use it. The [] capture list controls access to surrounding variables: [] captures nothing, [=] copies them, [&] references them. Lambdas power the STL algorithms you’ll meet later.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int threshold = 10;
// capture 'threshold' by value; take one int parameter
auto over = [threshold](int x) { return x > threshold; };
std::vector<int> v{3, 12, 7, 20};
int count = std::count_if(v.begin(), v.end(), over);
std::cout << count << " values over " << threshold << "\n"; // 2 ...
return 0;
}You can give operators meaning for your own types so they read like built-ins. Here + adds two vectors and << prints one. Overload operators only when the meaning is obvious — surprising operators hurt readability.
#include <iostream>
struct Vec2 {
double x, y;
Vec2 operator+(const Vec2& o) const { return {x + o.x, y + o.y}; }
};
std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << '(' << v.x << ", " << v.y << ')';
}
int main() {
Vec2 a{1, 2}, b{3, 4};
std::cout << a + b << "\n"; // (4, 6)
return 0;
}