기존수업에서 함수는 코드영역에 저장되고 컴파일 타임에 미리 생성이되며 주소를 갖는다고 배웠다.
이번에조사할 과제는 그 함수에 관련된 조사이다.
함수는 주소를 가지고있다 했고.. 포인터는 주소를 담는다고 했고.. 과연 함수 포인터가 무엇인지 알아보자.
함수 포인터 ?
함수는 다른 변수들 처럼 '주소' 를 가지고 있다.
이 함수의 주소를 포인터 변수에 저장하여 사용이 가능한 것을 '함수 포인터' 라고 한다.
아래의 예제를 통하여 선언의 형태를 확인하자.
●코드 예제1
int (*f)(int, int);
// int 리턴타입
// (*f) 변수의 이름 f 를 함수포인터로 선언
// (int, int) 함수의 매개변수
위처럼 선언하면 함수의 주소값을 저장할 수 있는 ' f ' 라는 함수 포인터가 만들어지게 된다.
이 ' f ' 라는 포인터 안에 함수의 ' 주소 ' 를 저장하여 사용이 가능하다.
사용방법은 코드 예제2 를 참조하자!
●코드 예제2
#include<iostream>
using namespace std;
int add(int a, int b)
{
return(a + b);
}
int main()
{
int (*f)(int, int);
f = add; // 전역에있는 함수 add 를 함수포인터 'f' 에 저장!
cout << f(1, 2) << endl; // add 함수를 f가대체하고 매개변수는 int a, int b !!
// 반환값은 a + b 이므로 출력은 3이될것으로 예상된다!
return 0;
}
●코드 예제2 출력결과
간단한 예제를 통하여서보니 조금 이해가된다.
이제 조금더 어려운 예제를 보도록 한다.
매개변수로 사용 할 수 있는 함수 포인터!
제목만봐도 조금 어려울 것 같다...
함수 포인터도 다른 변수처럼 매개변수로 사용이 가능하다고 한다..
아래의 예제를 보도록 하자.
●코드 예제3
#include<iostream>
using namespace std;
int add(int a, int b)
{
return(a + b);
}
void print_odd(int a, int b, int (*f)(int, int)) // 매개변수에 함수 add 사용!
{
int ret = f(a, b);
if ((ret % 2) == 1) // a + b 를 2로 나눈 나머지가 1이 아니라면(짝수라면)
cout << ret << endl; // 그 수를 출력
else // 짝수라면 홀수가 아니다 출력
cout << "홀수가 아니다!" << endl;
}
int main()
{
print_odd(2, 4, add);
print_odd(2, 3, add);
}
●코드 예제3 출력결과
함수 포인터의 const
요새 너무 자주보는 것 같은 const ... 또나왔다.
갑자기 const 와 static 의 개념이 햇갈려버렸다.
잊지않게 명시해두자.
const
- 대상을 변하지않는 '상수' 로 선언한다.
- 한번 값을 할당 하면 다른곳에서 변경이 불가능하다!
static
- '정적' 선언 ( 자동 주기 에서 -> 정적 주기로 변경된다)
- 변수에 선언시 스코프가종료되도 남아있으며 프로그램 종료시 소멸된다
- 한번만 초기화 할 수 있다.
이것저것 햇갈리는게 너무 많은 것 같다..
이제 다시 함수 포인터의 const 부분으로 넘어가자.
위에서 봤다싶이 상수로 선언 시키는 것과 관련이 있는 것 같다.
함수포인터도 다른 변수들처럼 ' const ' 를 사용 할 수 있다고 한다.
아래 코드를 통하여 확인하자
●코드 예제4
#include<iostream>
using namespace std;
int add(int a, int b)
{
return(a + b);
}
int main(void)
{
int (* const f)(int, int) = add;
// 참조 연산자 *옆에 const를 붙여주면 함수포인터 f를 상수화 시킬 수 있다!
cout << f(1, 2) << endl;
cout << f(3, 4) << endl;
cout << f(6, 7) << endl;
}
●코드 예제4 출력결과
class 멤버함수의 함수포인터 사용
그간 공부하면서 들어봤던것들 다나오는 느낌이다... 이번에는 class의 차례 같다.
class의 멤버함수도 함수포인터로 사용이 가능하다.
그러나 class 내부의 멤버함수는 ' 객체 ' 를 통해서만 출력이 가능하며
함수포인터의 선언 또한 해당 클래스의 ' 범위 ' 내에있는 함수포인터라고 명시해야 사용이 가능하다.
●코드 예제5
#include<iostream>
using namespace std;
class Sample
{
public:
int add(int a, int b) // 클래스 Sample 안에 멤버함수 add 가 있다!
{
return (a + b);
}
};
int main(void)
{
Sample sample; // Sample 클래스를 인스턴스화 시킨뒤 객체생성
int (Sample::*f)(int, int) = &Sample::add; // 와....
// 함수포인터 'f' 는 Sample 멤버함수를 사용한다고 'Sample::' 처럼 명시한다.
// 함수의 주소 또한 Sample 의 멤버함수임을 명시한다.
// 함수 주소를 가져올때는 '&' 레퍼런스 연산자를 통하여 주소를 가져온다.
cout << (sample.*f)(1, 2) << endl;
cout << (sample.*f)(3, 4) << endl;
cout << (sample.*f)(5, 6) << endl;
// 함수포인터의 사용시 해당 클래스의 객체를 통해서 사용한다.
// class 멤버함수 내에서 함수포이넡를 사용한다면 this 를 통하여 접근이 가능하다.
// 접근은 멤버 포인터 연산자인 '.*' 또는 '->*' 연산자로 접근해야 한다.
}
●코드 예제5 출력결과
static을 이용한 멤버함수의 접근
위에서 const static 에 혼란이있다했는데 ... 여기 나왔다. 이렇게된거 한번더 확인하자.
const
- 대상을 변하지않는 '상수' 로 선언한다.
- 한번 값을 할당 하면 다른곳에서 변경이 불가능하다!
static
- '정적' 선언 ( 자동 주기 에서 -> 정적 주기로 변경된다)
- 변수에 선언시 스코프가종료되도 남아있으며 프로그램 종료시 소멸된다
- 한번만 초기화 할 수 있다.
class 에서 멤버함수에 ' static ' 을 사용하면 class의 ' 이름 ' 으로 해당 함수에 접근이 가능하며
특정 객체에 ' 귀속 ' 되는 것이 아니다.
때문에 class의 이름을 통해서 접근만 해주면 일반 함수포인터와 동일하게 사용이 가능하다.
코드가 조금 길지만 이해할수 없는게 아니다! 잘 보도록 하자!
●코드 예제6
#include<iostream>
using namespace std;
class Sample // 더하기 클래스
{
public:
static int add(int a, int b)
{
return (a + b);
}
};
class Sample2 // 빼기 클래스
{
public:
static int sub(int a, int b)
{
return (a - b);
}
};
class Sample3 // 나누기 클래스
{
public:
static int div(int a, int b)
{
return (a / b);
}
};
class Sample4 // 곱하기 클래스
{
public:
static int mul(int a, int b)
{
return (a * b);
}
};
int main(void)
{
//함수포인터의 배열을 선언 후, class 이름을 통해서 함수의 주소를 저장한다.
int(*f[4])(int, int) = // 함수포인터에 배열선언 신기하다
{
&Sample::add, // f[0]
&Sample2::sub, // f[1]
&Sample3::div, // f[2]
&Sample4::mul // f[3]
};
for (int i = 0; i < 4; i++) // 0 1 2 3 까지
{
cout << f[i](1, 2) << endl;
// 출력은 일반 함수 포인터와 동일하다.
}
}
●코드 예제6 출력결과
조금은 복잡할것같은 코드를 사용하여 나온 결과가 사칙연산이라 조금 김이 빠지지만 신기하다.
한번에 모든 것을 이해할 수 없다. 모르더라도 한번씩보고 보는동안 원리를 이해하려고 노력 하자.
'공부' 카테고리의 다른 글
C++ 메모리영역 복습 (1) | 2022.12.01 |
---|---|
C++ static & const 복습 (0) | 2022.12.01 |
C++ 생성자(복사,이동,push_back,emplace_back) (0) | 2022.11.30 |
C++ 파라미터와 인자의 차이점 (1) | 2022.11.30 |
C++ 샵&인벤토리 아이템 수량 추가 (0) | 2022.11.29 |
댓글