C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
17: Default Arguments
I want to show you something that trips up almost every C++ developer when they first start splitting their code into header files and implementation files. It's a subtle compiler error that feels like the computer is lying to you.
// GameUtils.h
void spawnEnemy(std::string name, int health);
// GameUtils.cpp
void spawnEnemy(std::string name, int health = 100) {
// Logic to place enemy in the world...
}
// main.cpp
int main() {
spawnEnemy("Goblin"); // Error: too few arguments to function call
return 0;
}
The 'Too Few Arguments' Headache
If you try to compile this, your compiler is going to scream at you in main.cpp. It will tell you that spawnEnemy expects two arguments, but you only gave it one. You'll probably look at GameUtils.cpp, see that health = 100 is right there, and wonder why the compiler is ignoring it.
Here is the deal: the compiler processes files individually. When it's compiling main.cpp, it doesn't look at the implementation in the .cpp file; it only looks at the declaration in the .h file. Since the header says spawnEnemy requires a name and health, the compiler assumes you've made a mistake. It has no idea that a default value exists because you hid it in the implementation file.
Moving Defaults to the Declaration
To fix this, you have to move the default value to the function declaration (the prototype). This tells any file including that header exactly what the default is so it can "fill in the blank" during compilation.
// GameUtils.h
// The default goes here!
void spawnEnemy(std::string name, int health = 100);
// GameUtils.cpp
// Do NOT repeat the default value here
void spawnEnemy(std::string name, int health) {
// Logic to place enemy in the world...
}
Now, when main.cpp sees spawnEnemy("Goblin"), the compiler checks the header, sees that health is optional and defaults to 100, and effectively rewrites your call to spawnEnemy("Goblin", 100) behind the scenes. Note that I removed the = 100 from the .cpp file; C++ doesn't allow you to define the default in both places, as that would be redundant and potentially conflicting.
The Trap of Out-of-Order Arguments
There's one more rule you need to keep in mind. Default arguments must always be the rightmost parameters. You can't have a "gap" in your arguments.
Imagine you tried to do this:
void setPlayerPosition(int x = 0, int y, int z = 0); // This will NOT compile
The compiler would have no idea what to do if you called setPlayerPosition(10, 20). Does the 20 go to y (meaning x stays 0), or does the 10 go to x and 20 go to z (meaning y is missing)? To avoid this ambiguity, C++ requires that once you provide a default value for one parameter, every single parameter to the right of it must also have a default value.
I personally use default arguments sparingly. They're great for optional configuration, but if you find yourself with ten different default arguments, you're probably better off creating a Config struct to pass into the function instead. It keeps the call sites much cleaner.
📋 Practical Task
Building a Flexible System Logger
You are tasked with creating a logging utility for a software project. The goal is to allow developers to log messages with different severity levels, but since "Info" is the most common level, it should be the default.
Requirements:
- Create a function called
logMessage. - It should take two parameters: a
std::string messageand anint level. - The
levelparameter should have a default value of1(representing "Info"). - The function should print the level and the message to the console (e.g.,
"[Level 1] System started"). - In your
mainfunction, demonstrate two calls: one where you provide only the message, and one where you override the default level to3(representing "Error").
There are no comments for now.