C++ Default Arguments | 'Default Arguments' Guide
이 글의 핵심
Default arguments allow optional parameters in a single function signature. Organizes declaration/redeclaration rules, pitfalls with overloading/virtual functions, and API design patterns.
What are Default Arguments?
Default arguments allow specifying default values for function parameters, enabling argument omission during calls. Can replace function overloading to make code more concise.
Below is an implementation example using C++. Try running the code directly to check its operation.
void greet(const std::string& name = "Guest") {
std::cout << "Hello, " << name << "!" << std::endl;
}
int main() {
greet("Alice"); // Hello, Alice!
greet(); // Hello, Guest!
}
Why needed?:
- Conciseness: Implement optional parameters without overloading
- Backward compatibility: Maintain existing code when adding new parameters
- Readability: Set frequently used values as defaults
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ❌ Overloading: Code duplication
void connect(const std::string& host) {
connect(host, 8080);
}
void connect(const std::string& host, int port) {
// Connection logic
}
// ✅ Default argument: Concise
void connect(const std::string& host, int port = 8080) {
// Connection logic
}
Basic Usage
Here is detailed implementation code using C++. Understand the role of each part while examining the code.
// Single default argument
void func(int x = 10) {
std::cout << x << std::endl;
}
// Multiple default arguments
void func(int x = 10, int y = 20, int z = 30) {
std::cout << x << ", " << y << ", " << z << std::endl;
}
int main() {
func(); // 10, 20, 30
func(1); // 1, 20, 30
func(1, 2); // 1, 2, 30
func(1, 2, 3); // 1, 2, 3
}
Rules
Below is an implementation example using C++. Understand the role of each part while examining the code.
// ✅ Defaults from right
void func(int x, int y = 20, int z = 30) {
// OK
}
// ❌ Gap in middle
// void func(int x, int y = 20, int z) { // Error
// // ...
// }
// ✅ All defaults
void func(int x = 10, int y = 20, int z = 30) {
// OK
}
Default Argument Rules in Detail:
- Continuous from right: Parameters with default values must be continuous from right.
Below is an implementation example using C++. Try running the code directly to check its operation.
// ✅ Correct examples
void f1(int a, int b = 2, int c = 3);
void f2(int a = 1, int b = 2, int c = 3);
// ❌ Incorrect examples
// void f3(int a = 1, int b, int c = 3); // Error: b has no default in middle
// void f4(int a = 1, int b, int c); // Error: only a has default
- Defaults only in declaration: Specify default values only in header file declaration, omit in implementation file.
Below is an implementation example using C++. Try running the code directly to check its operation.
// header.h
void func(int x, int y = 20);
// source.cpp
void func(int x, int y) { // No default value
std::cout << x << ", " << y << '\n';
}
- Can add defaults in redeclaration: Can add default values in redeclaration for same parameter, but duplicate specification not allowed.
Below is an implementation example using C++. Understand the role of each part while examining the code.
void func(int x, int y, int z); // Declaration 1
void func(int x, int y, int z = 30); // Declaration 2: Add default to z
void func(int x, int y = 20, int z); // Declaration 3: Add default to y
// Final: func(int x, int y = 20, int z = 30)
// ❌ Duplicate specification
// void func(int x, int y = 20, int z = 30); // Error: y, z duplicate
Constraints and Pitfalls with Virtual Functions
Default arguments are not virtual. Even in virtual function calls, which default value is used is determined at compile-time by the static type used in the call.
Below is an implementation example using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
// Type definition
struct Base {
virtual void f(int x = 1) { std::cout << "B " << x << '\n'; }
};
struct Derived : Base {
void f(int x = 2) override { std::cout << "D " << x << '\n'; }
};
int main() {
Derived d;
Base& b = d;
d.f(); // D 2 — Static type Derived → Derived's default
b.f(); // D 1 — Static type Base → Base's default (not derived's!)
}
Having different default values in override function in derived class is syntactically possible, but only confuses users calling through base pointer. In public API, safer to put default values only in base declaration and omit in derived, or handle defaults with non-virtual wrapper.
Also, when overriding virtual function with default arguments, signature (name·parameter list) must match, so default value list must align with header design separate from inheritance rules.
Practical Examples
Example 1: Log Function
Here is detailed implementation code using C++. Import the necessary modules and perform branching with conditionals. Understand the role of each part while examining the code.
#include <iostream>
#include <fstream>
#include <string>
enum class LogLevel {
INFO,
WARNING,
ERROR
};
void log(const std::string& message,
LogLevel level = LogLevel::INFO,
const std::string& file = "log.txt") {
std::ofstream ofs(file, std::ios::app);
switch (level) {
case LogLevel::INFO:
ofs << "[INFO] ";
break;
case LogLevel::WARNING:
ofs << "[WARNING] ";
break;
case LogLevel::ERROR:
ofs << "[ERROR] ";
break;
}
ofs << message << '\n';
}
int main() {
log("Application started"); // Default: INFO, log.txt
log("Low memory", LogLevel::WARNING); // WARNING, log.txt
log("Crash", LogLevel::ERROR, "error.txt"); // ERROR, error.txt
}
Summary
Key Points
- Default arguments: Specify default values for parameters
- Rules: Continuous from right, declaration only
- Virtual functions: Defaults determined by static type
- Overloading: Can cause ambiguity
- API design: Use for 2-3 parameters max
When to Use
✅ Use default arguments when:
- Need optional parameters
- Want to maintain backward compatibility
- Have frequently used default values
- Simplifying overload set
❌ Don’t use when:
- Too many parameters (use options struct)
- Virtual function with different defaults
- Causes ambiguity with overloads
- Expression has side effects
Best Practices
- ✅ Put defaults in header declaration
- ✅ Keep defaults simple and constant
- ✅ Limit to 2-3 default parameters
- ❌ Don’t use different defaults in virtual override
- ❌ Don’t use expressions with side effects
Related Articles
Master default arguments for cleaner function APIs! 🚀
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Default arguments allow optional parameters in a single function signature. Organizes declaration/redeclaration rules, p… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ 함수 오버로딩 | ‘Function Overloading’ 가이드
- C++ constexpr if | ‘컴파일 타임 분기’ 가이드
- C++ constexpr Lambda | ‘컴파일 타임 람다’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, default-arguments, function, default-value 등으로 검색하시면 이 글이 도움이 됩니다.