C++에서 함수 포인터는 함수자(functor)를 구현할 때 유용하게 사용되며 STL이나 콜백 메커니즘을 구현할 때도 유용하게 사용될 수 있습니다.
1, 함수 포인터의 종류
C++언어의 함수는 세 가지 방식으로 호출할 수 있습니다.
- 첫째, 정적 함수 호출(전역함수, 클래스 내의 정적함수, 네임 스페이스 내의 전역함수등)
- 둘째, 객체로 멤버 함수 호출(객체 자체로 호출)
- 셋째, 객체의 주소로 멤버 함수 호출(객체의 주소로 호출)
위 세 가지에 대한 함수 포인터 선언및 호출 방식이 다릅니다.
우리는 이미
첫째, 정적 함수의 주소를 저장하는 함수 포인터는 알고 있습니다.
여기서 다시 복습해 볼까요?
using namespace std;
class Point
{
int x, y;
public:
// ... 여러 멤버들 ..
static void Print(int n) // 2.Point 클래스 static 함수
{
cout << "n = " << n << endl;
}
};
void Print(int n) // 1.전역 함수
{
cout << "n = " << n << endl;
}
namespace NetGong
{
void Print(int n) // 3.NetGong 네임스페이스 내의 전역함수
{
cout << "n = " << n << endl;
}
}
void main( )
{
void (*pfunc)(int ); // 함수 포인터 선언 - C언어 QuickStart1 참고
pfunc = &Print; // 1.전역함수 주소 저장
pfunc( 10 ); // 1.전역함수 호출
pfunc = &Point::Print; // 2.Point 클래스 static 함수 저장
pfunc( 10 ); // 2.Point 클래스 static 함수 호출
pfunc = &NetGong::Print; // 3.NetGong 네임스페이스 내의 전역함수 저장
pfunc( 10 ); // 3.NetGong 네임스페이스 내의 전역함수 호출
}
- n = 10
n = 10
n = 10
뭐.. 별로 설명할 것이 없습니다.
알아 둘 것은 위 세 가지 경우 모두 같은 포인터 변수를 사용한다는 것입니다. 호출 방식이 같거든요.
함수의 주소를 저장할 때 Print가 함수 주소이므로 &Print 와 같이 &를 붙여도 그만 붙이지 않아도 그만이지만 명시적으로 &붙여 사용합니다. 연산자의 위치와 용도에 따라 의미가 달라지는 걸 아시죠? 이곳에서 &가 있든 없든 같은 코드입니다. 또, 아래쪽에서 배울 맴버함수는 꼭 & 연산자가 있어야 합니다. 하여튼 &를 붙이는 방식을 선호하므로 꼭 붙여서 사용하는 습관을 들이세요.
이제 둘째, 셋째 멤버 함수호출인 멤버 함수 포인터를 사용하는 예제를 공부해 보도록 하겠습니다.
- 멤버 함수 포인터 선언
class Point{
//멤버 ...
void Print( )
{
cout << "(" << x << "," << y << ")" << endl;
}
};
void (Point::*pfunc)( ); //멤버 함수 주소를 저장하기 위한 함수 포인터 선언
일반 함수 포인터라면 void (*pfunc)( ); 라고 선언했겠지만 Point 클래스의 멤버 함수 포인터이므로 Point::* 와 같은 연산자를 사용합니다.
멤버 함수 포인터를 이용한 호출
- 객체로 호출 : (객체.*pfunc)( );
- 객체의 주소로 호출 : (객체주소->*pfunc)( );
.* 연산자와 ->*연산자를 이용하여 각각 객체와 객체의 주소로 함수 포인터가 가리키는 멤버함수를 호출할 수 있습니다. 또 연산자 우선순위 때문에 ( )로 묶어 주어야합니다. 주의하세요.
2, 멤버 함수 포인터 실습
그럼 실제 함수 포인터 예제를 보도록 하겠습니다.
using namespace std;
class Point
{
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) { }
void Print( )
{
cout << "(" << x << "," << y << ")" << endl;
}
};
void main( )
{
Point d1(2,3);
Point *p = &d1;
void (Point::*pfunc)( ); //멤버 함수 주소를 저장하기 위한 함수 포인터 선언
pfunc = &Point::Print;
d1.Print(); //둘째, 객체로 멤버 함수 호출
p->Print(); //셋째, 객체의 주소로 멤버 함수 호출
(d1.*pfunc)( ); //둘째, 객체로 함수 포인터 이용한 멤버 함수 호출
(p->*pfunc)( ); //셋째, 객체의 주소로 함수 포인터 이용한 멤버 함수 호출
Point d2, d3(5,5);
(d2.*pfunc)();
(d3.*pfunc)();
}
- (2,3)
(2,3)
(2,3)
(2,3)
(0,0)
(5,5)
객체는 연산자 .*를 사용하고 객체의 주소는 ->* 연산자를 사용한다는 것만 주의하세요.
또 다른 예제를 보겠습니다.
using namespace std;
class Point
{
int x, y;
public:
Point(int _x = 0, int _y = 0) : x(_x), y(_y) { }
bool Compare(const Point& arg)
{
return x==arg.x && y == arg.y ? true : false ;
}
void Print( )
{
cout << "(" << x << "," << y << ")" << endl;
}
};
void main( )
{
Point d1(2,3);
Point d2(5,5);
Point *p = &d1;
bool (Point::*pfunc)(const Point& ); //멤버 함수 주소를 저장하기 위한 함수 포인터 선언
pfunc = &Point::Compare;
cout << d1.Compare(d2) << endl; //둘째, 객체로 멤버 함수 호출
cout << p->Compare(d1) << endl; //셋째, 객체의 주소로 멤버 함수 호출
//둘째, 객체로 함수 포인터 이용한 멤버 함수 호출
cout << (d1.*pfunc)(d2) << endl;
//셋째, 객체의 주소로 함수 포인터 이용한 멤버 함수 호출
cout << (p->*pfunc)(d1) << endl;
}
- 0
1
0
1
'Basic Programming > C, C++' 카테고리의 다른 글
C++ - 함수 포인터와 함수자 - 3 (0) | 2016.04.18 |
---|---|
C++ - 함수 포인터와 함수자 - 2 (0) | 2016.04.15 |
C++ - void 포인터, 함수 포인터 (1) | 2016.04.04 |
C++ - 비트맵(bmp) 저장 및 불러오기 (0) | 2016.03.29 |
C++ - Windows Keyboard Codes (키보드 코드) (0) | 2016.03.24 |