3.1 인라인 함수
함수 호출에 따른 시간 오버헤드
인라인 함수란?
함수 호출 시 발생하는 오버헤드를 줄이기 위해서 함수를 호출하는 대신 함수가 호출되는 곳마다 함수의 코드를 복사하여 넣어주는 특별한 함수
인라인 함수
인라인 함수
- 함수의 선언이나 정의에 inline 키워드를 지정하여 선언된 함수
인라인 함수에 대한 처리
- 인라인 함수를 호출하는 곳에 인라인 함수 코드를 확장 삽입
- 매크로와 유사 (매크로는 전처리 과정에서 이루어짐)
- 코드 확장 후 인라인 함수는 사라짐 (컴파일 과정에서 사라짐)
- 인라인 함 수 호출
- 함수 호출에 따른 옵버헤드 존재하지 않음
- 프로그램의 실행 속도 개선
- 컴파일러에 의해 이루어짐
인라인 함수의 목적
C++ 프로그램의 실행 속도 향상
- 자주 호출되는 짧은 코드의 함수 호출에 대한 시간 소모를 줄임
- C++에는 짧은 코드의 멤버 함수가 많기 때문
인라인 함수의 사용 예
컴파일러에 의한 코드 대치
인라인 함수 vs 매크로 함수
매크로 함수와 인라인 함수의 차이점
- 매크로 함수 -> 전처리기에 의한 문자열 대치 방식
- 인라인 함수 -> 컴파일러에 의한 코드 대치 방식
매크로 함수의 문제점
- 연산자 우선 순위 문제
- 인자의 형 검사를 하지 않음
-> 인라인 함수를 사용하는 것이 좋다.
인라인 함수의 장단점
장점
- 프로그램의 실행 시간이 빨라진다.
단점
- 인라인 함수 코드의 삽입으로 컴파일된 전체 코드 크기 증가 (바이너리 코드가 증가해서 실행 파일의 크기가 증가)
- 통계적으로 최대 30% 증가
- 짧은 코드의 함수를 인라인으로 선언하는 것이 좋음
3.2 디폴트 인자
디폴트 인자(default parameter)
디폴트 인자란?
- 인자에 값이 넘어오지 않는 경우, 디폴트 값을 받도록 선언된 인자
- '인자 = 디폴트값' 형태로 선언
디폴트 인자를 지정할 때는 함수의 선언부에 지정
- 디폴트 인자를 지정할 때는 인자형, 인자 이름 다음에 = 과 함께 디폴트 값을 지정한다.
- 함수를 정의할 때는 기존 함수를 정의하는 방법대로 함
void default_sample(char c, int i, double d = 0.5); // 함수 선언부, double d = 0.5 가 디폴트 인자
void main(){
default_sample('X', 10);
default_sample('Y', 30, 2.0);
}
디폴트 인자에 관한 제약 조건
디폴트 인자 지정 순서
- 함수의 가장 오른쪽 인자부터 지정해야 한다.
void foo1(char c, int i, double d);
void foo2(char c, int i, double d = 0.5);
void foo3(char c, int i = 10, double d = 0.5);
void foo4(char c = 'A', int i = 10, double d = 0.5);
함수 인자의 생략
- 함수의 가장 오른쪽 인자부터 생략해야 한다.
void foo(char c = 'A', int i = 10, double d = 0.5);
foo('A', 20); // 세 번째 인자만 생략함
foo('B'); // 두 번째, 세 번째 인자만 생략함
foo(); // 인자 모두 생략
디폴트 인자 사례
3.3 함수 중복 (오버로딩)
함수의 중복
함수 중복 = 함수 오버로딩(function overloading)\
- 이름은 같지만 인자의 개수나 데이터 형이 다른 함수를 여러 번 정의할 수 있는 기능
- 다형성
- C언어에서는 불가능
- 함수 중복 기능을 사용하면 같은 이름을 갖는 함수를 내용물이 다르도록 여러 번 정의할 수 있다.
- 각각의 함수는 인자의 시그니처(인자의 개수나 인자의 데이터 형)가 반드시 달라야 한다.
- 함수 호출 시 전달된 인자의 데이터 형으로 컴파일러가 어떤 함수를 호출할 지를 결정
함수 중복 성공 조건
- 중복된 함수들의 이름 동일
- 중복된 함수들의 매개 변수 타입이 다르거나 개수가 달라야 함
- 리턴 타입은 함수 중복과 무관
함수 중복 성공 사례
함수 중복 실패 사례
리턴 타입이 다르다고 함수 중복이 성공하지 않는다.
함수 중복의 편리함
동일한 이름을 사용하면 함수 이름을 구분하여 기억할 필요가 없고, 함수 호출을 잘못하는 실수를 줄일 수 있음
함수 중복 시 주의사항
인자의 이름만 다른 경우 오버로딩 할 수 없다.
int foo1(int a, int b);
int foo1(int x, int y);
foo1(10, 20); // 에러
함수의 리턴형만 다른 경우 오버로딩 할 수 없다.
int foo2(char c, int num);
void foo2(char c, int num);
foo2('A', 20); // 에러
데이터 형과 해당 형의 레퍼런스 형으로 오버로딩된 경우 오버로딩 할 수 없다.
int foo3(int a, int b);
int foo3(int &a, int &b);
int x = 10, y = 20;
foo3(x, y); // 에러
// foo3(10, 20); 은 가능하다.
// 왜냐하면 리터럴이기 때문이다. int foo3(int a, int b);가 호출된다.
typedef로 정의된 데이터 형에 대해 오버로딩된 경우 오버로딩 할 수 없다.
typedef unsigned int UINT;
void foo4(UINT a, UINT b);
void foo4(unsigned int a, unsigned int b);
foo4(10, 20); // 에러
디폴트 인자에 의해서 인자의 개수가 같은 경우 오버로딩 할 수 없다.
void foo5(int a);
void foo5(int a, int b = 0);
foo5(10); // 에러
디폴트 인자 vs 함수 중복
디폴트 인자의 사용
- 두 함수의 처리 과정이 비슷하고 한 함수가 다른 함수의 특별한 경우로 간주되는 경우
int GetSum(int x, int y, int z = 0){ // 디폴트 인자 지정
return x + y + z;
}
int main(){
GetSum(10, 20);
GetSum(10, 20, 30);
}
함수 오버로딩의 사용
- 두 함수의 구체적인 처리 과정이 다르지만 같은 함수 이름으로 표현될 수 있다는 공통점만 갖는 경우
int GetSum(int x, int y){
return x + y;
}
int GetSum(const int arr[], int size){
int sum = 0;
for(int i=0; i<size; i++)
sum += arr[i];
return sum;
}
디폴트 인자를 사용한 함수 중복 간소화
3.4 함수 템플릿
함수 중복의 약점 - 중복 함수의 코드 중복
일반화와 템플릿
참고) 원래 헤더 파일에 정의해야 됨
제네릭(generic) 또는 일반화
- 함수나 클래스를 일반화시키고, 매개 변수 타입을 지정하여 틀에서 찍어 내듯이 함수나 클래스 코드를 생산하는 기법
템플릿
- 함수나 클래스를 일반화하는 C++ 도구
- template 키워드로 함수나 클래스 선언
- 변수나 매개 변수의 타입만 다르고, 코드 대부분이 동일한 함수를 일반화시킴
- 제네릭 타입 - 일반화를 위한 데이터 타입
템플릿 선언
중복 함수들로부터 템플릿 만들기 사례
템플릿으로부터의 구체화
구체화(specialization)
- 템플릿의 제네릭 타입에 구체적인 타입 지정
- 템플릿 함수로부터 구체화된 함수의 소스 코드 생성 -> 코드량이 증가한다.
제네릭 함수로부터 구체화된 함수 생성 사례
템플릿으로부터 구체화 예시
암시적 인스턴스화 -> 컴파일러가 유추함
cout<<GetMax(10, 20)<<endl; // T = int
char ch = GetMax('A', 'B'); // T = char
cout<<GetMax(3.14, 10.5)<<endl; // T = double
cout<<GetMax(5, 10.5)<<endl; // 컴파일 에러
명시적 인스턴스화
cout<<GetMax<int>(5, 10.5)<<endl; // T = int
cout<<GetMax<double>(5, 10.5)<<endl; // T = double
구체화 오류
제네릭 타입에 구체적인 타입 지정 시 주의
템플릿 장단점과 제네릭 프로그래밍
템플릿 장점
- 함수 코드의 재사용
- 높은 소프트웨어의 생산성과 유용성
템플릿 단점
- 포팅에 취약 (포팅: 다른 플랫폼이나 환경으로 소프트웨어를 이식하는 것)
- 컴파일러에 따라 지원하지 않을 수 있음
- 컴파일 오류 메시지 빈약, 디버깅에 많은 어려움
제네릭 프로그래밍
- generic programming
- 일반화 프로그래밍이라고도 부름
- 제네릭 함수나 제네릭 클래스를 활용하는 프로그래밍 기법
- C++에서 STL(Standard Template Library) 제공, 활용
- 보편화 추세
- Java, C# 등 많은 언어에서 활용
템플릿 함수보다 중복 함수가 우선
'공부 > C++' 카테고리의 다른 글
5. 생성자와 소멸자 (0) | 2024.04.11 |
---|---|
4. 클래스와 객체의 기본 (0) | 2024.04.09 |
2. 포인터와 레퍼런스 (1) | 2024.03.30 |
1. C++ 프로그래밍의 기본 (2) | 2024.03.26 |
0. C++ 시작 (0) | 2024.03.24 |