기본 매개변수
함수 오버로딩은 유용하지만, 매개변수의 개수나 타입이 조금씩 다른 여러 함수를 반복해서 정의해야 하는 경우도 있습니다.
예를 들어 거의 동일한 작업을 수행하지만, 몇몇 선택적인 매개변수만 다르게 전달하고 싶을 때 말이죠.
이러한 상황에서 코드의 중복을 줄이고 함수 호출을 더욱 유연하게 만드는 C++의 기능이 바로 기본 매개변수(Default Arguments)입니다.
이 장에서는 기본 매개변수가 무엇인지, 어떻게 사용하는지, 사용 시 주의할 점을 다룹니다.
기본 매개변수란 무엇인가?
기본 매개변수는 호출에서 생략된 인자를 선언에 적힌 기본값으로 채우는 기능입니다. 따라서 기본값을 어디에 선언하는지, 오른쪽부터 붙였는지, 오버로딩과 호출 형태가 겹치지 않는지를 함께 확인해야 합니다.
기본 매개변수는 함수를 선언하거나 정의할 때, 특정 매개변수에 기본값(default value)을 지정하는 기능입니다.
이렇게 기본값이 지정된 매개변수는 함수를 호출할 때 해당 인자를 생략할 수 있습니다.
만약 인자가 생략되면 컴파일러는 매개변수에 지정된 기본값을 자동으로 사용합니다.
반환타입 함수이름(타입1 매개변수1, 타입2 매개변수2 = 기본값2, 타입3 매개변수3 = 기본값3);- 기본값은 상수, 전역 변수, 또는 다른 함수의 호출 결과 등이 될 수 있습니다.
- 중요: 기본 매개변수는 항상 오른쪽에서부터 왼쪽으로 순서대로 지정되어야 합니다. 즉, 기본값이 없는 매개변수 뒤에는 기본값이 있는 매개변수가 올 수 없습니다.
// int func(int a = 10, int b); // 오류: 기본값 없는 매개변수 b가 기본값 있는 매개변수 a 뒤에 있음
// int func(int a, int b = 20, int c); // 오류: 기본값 없는 매개변수 c가 기본값 있는 매개변수 b 뒤에 있음int func(int a, int b = 20, int c = 30); // OK
int func(int a, int b, int c = 30); // OK
int func(int a = 10, int b = 20, int c = 30); // OK기본 매개변수의 필요성
- 함수 오버로딩의 대안: 매개변수 몇 개만 다른 유사한 함수들을 여러 개 오버로딩하는 대신, 기본 매개변수를 사용하여 하나의 함수로 대체할 수 있습니다. 이는 코드 중복을 줄이고 유지보수를 용이하게 합니다.
- 유연한 함수 호출: 함수를 호출할 때 모든 인자를 항상 제공하지 않아도 되므로, 함수 사용이 더 편리해집니다.
- 선택적 인자 구현: 특정 매개변수가 대부분의 경우 동일한 값을 가지거나, 필수가 아닌 선택적 정보를 나타낼 때 유용합니다.
기본 매개변수 사용 예시
메시지와 함께 특정 횟수만큼 반복하는 함수를 만들어봅시다.
횟수를 지정하지 않으면 기본값(예: 1회)으로 출력하게 합니다.
#include <iostream>
#include <string>
// printMessage 함수: 메시지와 반복 횟수를 받지만, count에 기본값 1을 지정
void printMessage(const std::string& message, int count = 1) {
for (int i = 0; i < count; ++i) {
std::cout << message << std::endl;
}
}
int main() {
printMessage("Hello, C++!"); // count 생략 -> 기본값 1 사용
std::cout << "------------------" << std::endl;
printMessage("Welcome!", 3); // count를 3으로 지정
/* 출력:
Hello, C++!
------------------
Welcome!
Welcome!
Welcome!
*/
return 0;
}printMessage("Hello, C++!") 호출 시 count 인자를 생략했으므로, count는 기본값인 1이 됩니다.
printMessage("Welcome!", 3) 호출 시에는 count에 3이 명시적으로 전달되므로, 기본값은 무시되고 3이 사용됩니다.
그래픽 프로그램에서 창의 위치와 크기를 설정하는 함수를 만들어봅시다.
x, y 좌표와 width, height를 받는데, width와 height에 기본값을 줄 수 있습니다.
#include <iostream>
// x, y 좌표와 폭, 높이를 받는 함수
// 폭과 높이에 기본값을 설정
void setWindowSize(int x, int y, int width = 800, int height = 600) {
std::cout << "창 설정: X=" << x << ", Y=" << y
<< ", 폭=" << width << ", 높이=" << height << std::endl;
}
int main() {
setWindowSize(10, 20); // X=10, Y=20, 폭=800, 높이=600 (기본값 사용)
setWindowSize(50, 50, 1024); // X=50, Y=50, 폭=1024, 높이=600 (height 기본값 사용)
setWindowSize(0, 0, 1920, 1080); // X=0, Y=0, 폭=1920, 높이=1080 (모든 인자 명시)
/* 출력:
창 설정: X=10, Y=20, 폭=800, 높이=600
창 설정: X=50, Y=50, 폭=1024, 높이=600
창 설정: X=0, Y=0, 폭=1920, 높이=1080
*/
return 0;
}기본 매개변수와 함수 원형/정의
기본 매개변수는 함수 원형(declaration)에만 지정하거나, 함수 정의(definition)에만 지정할 수 있습니다.
두 곳 모두에 지정하면 컴파일 오류가 발생합니다. 일반적으로 함수 원형에 기본값을 지정하는 것이 권장됩니다.
이는 헤더 파일에 함수 원형을 선언할 때 기본값이 포함되어야 컴파일러가 함수 호출을 해석할 수 있기 때문입니다.
올바른 방법 (함수 원형에 기본값 지정)#pragma once
#include <string>
// 함수 원형에 기본 매개변수 지정
void printData(int value, char separator = '-', int repeat = 1);#include "my_printer.h"
#include <iostream>
// 함수 정의에는 기본 매개변수를 다시 지정하지 않음
void printData(int value, char separator, int repeat) {
for (int i = 0; i < repeat; ++i) {
std::cout << value;
if (i < repeat - 1) { // 마지막을 제외하고 구분자 출력
std::cout << separator;
}
}
std::cout << std::endl;
}#include "my_printer.h" // 원형이 있는 헤더 포함
int main() {
printData(10); // 10 (separator='-', repeat=1)
printData(20, '*'); // 20* (repeat=1)
printData(30, '#', 5); // 30#30#30#30#30
return 0;
}기본 매개변수와 함수 오버로딩의 관계
기본 매개변수는 함수 오버로딩과 함께 사용될 때 모호성(Ambiguity)을 유발할 수 있습니다.
컴파일러가 함수 호출에 대해 오버로딩된 여러 함수와 기본 매개변수를 가진 함수 중 어떤 것을 선택해야 할지 명확하지 않을 때 발생합니다.
#include <iostream>
#include <string>
void greet(std::string name) { // 오버로딩된 함수
std::cout << "안녕하세요, " << name << std::endl;
}
void greet(std::string name, std::string salutation = "안녕") { // 기본 매개변수를 가진 함수
std::cout << salutation << ", " << name << std::endl;
}
int main() {
// greet("홍길동"); // 컴파일 오류! 모호성 발생!
// greet(std::string)과 greet(std::string, std::string="안녕")
// 둘 다 greet("홍길동")에 매칭될 수 있기 때문
return 0;
}위 예시에서 greet("홍길동")을 호출하면, 컴파일러는 greet(std::string)을 호출할지, 아니면 두 번째 greet 함수에서 salutation 매개변수에 기본값을 사용하여 greet(std::string, std::string)을 호출할지 결정할 수 없습니다.
다음 판단 기준을 기준으로 기본 매개변수와 오버로딩이 충돌하는지 빠르게 점검할 수 있습니다.
이러한 모호성을 피하려면,- 기본 매개변수와 오버로딩된 함수들이 충돌하지 않도록 설계합니다.
- 모호성이 발생하면 명시적으로 원하는 함수를 호출하도록 인자를 모두 제공합니다.
결론: 기본 매개변수의 효율적인 활용
기본 매개변수는 함수의 유연성을 높이고 코드 중복을 줄이는 도구입니다.
특히 선택적인 인자를 가지는 함수나, 대부분의 경우 동일한 기본값을 사용하는 매개변수가 있을 때 매우 유용합니다.
하지만 올바른 위치에 선언하고, 함수 오버로딩과의 관계에서 발생할 수 있는 모호성에 주의해야 합니다.
현대 C++에서는 기본 매개변수를 사용하여 함수의 다양한 사용 시나리오를 간결하게 표현하는 것이 일반적인 관례입니다.
기본 매개변수는 호출을 짧게 만드는 대신, 선언 위치와 오버로드 충돌을 더 엄격하게 관리해야 합니다. 다음 요약표로 기본값을 붙이기 전 확인 순서를 점검해 봅시다.