본문 바로가기
C++ STL/Part 01 C++ 문법

2장 함수 포인터

by 노오오오오옹 2021. 6. 17.

2. 함수 포인터

2-1. 함수 포인터란

  • 변수 : 값을 저장하는 메모리 공간의 이름
  • 포인터 : 주소를 저장하는 메모리 공간의 이름
  • 함수 포인터 : 함수의 시작 주소를 저장하는 포인터
void Print(int num)
{
    cout << "값 : " << num << endl;
}

int main()
{
    void (*pf)(int); // void(int num)이기 때문에 void(*이름)(int로) 선언
    pf = Print; // 함수의 이름으로 시작 주소를 설정
    
    pf(10); // 함수포인터 호출 1
    (*pf)(10); // 함수포인터 호출 2
}

 

2-2. 함수 포인터의 종류

함수는 정적 함수(전역, namespace내 전역, static)와 멤버 함수로 나뉜다. 또한, 멤버함수는 객체와 주소로 호출하기 때문에 총 3가지로 나뉜다.

  • 정적 함수 호출
  • 객체로 멤버함수 호출
  • 객체의 주소로 멤버 함수 호출
void Print()
{
    cout << "정적 함수" << endl;
}

class Point()
{
public:
    void Print()
    {
        cout << "멤버 함수" << endl;
    }
}

int main()
{
    Point pt;
    Point *ptr &pt;
    
    Print(); // 정적함수
    pt.Print(); // 객체를 통한 멤버함수
    ptr->Print(); // 주소를 통한 멤버함수
}

 

  • 정적 함수 호출

정적함수는 전역 함수, namespace내의 전역함수, static 함수 모두 같은 규악으로 호출한다.

// 함수반환 (*이름)(타입)
void (*pf)(int);
void Print()
{
    cout << "전역함수" << endl;
}

namespace A
{
	void Print()
    {
    	cout << "namespace내 전역함수" << endl;
    }
}

class Point()
{
public:
    static void Print()
    {
        cout << "클래스의 정적 멤버 함수" << endl;
    }
}

int main()
{
    void (*pf)(void);
    
    Print(); // 전역함수
    A::Print(); // namespace내 전역함수
    Point::Print(); // 클래스의 정적 멤버 함수 
    
    pf = Print;
    pf();
    pf = A::Print;
    pf();
    pf = Point::Print;
    pf();
}

 

  • 객체와 주소로 멤버 함수 호출

멤버 함수 포인터는 함수 포인트 선언에 어ㅏ떤 클래스의 멤버 함수를 가리킬 것인지, 클래스를 선정해야한다.

  • * 객체로 멤버함수 호출(.* 연산자) : (객체.*pf)(10)
  • * 주소로 멤버함수 호출(->* 연산자) : (주소->*pf)(10)
class Point()
{
    int x;
    int y;
    
public:
    explicit Point(int a=0, int b=0) : x(a), y(b) {}
    
    void Print() const { cout << x << ',' << y << endl; }
    void PrintInt(int n) const { cout << "정수 : " << n << endl; }
}

int main()
{
    Point pt(2,3);
    Point* ptr = &pt;
    
    // 반환타입(클래스 이름::*포인터 함수 이름)(인수 타입)
    void(Point::*pf1)() const;
    void(Point::*pf2)(int) const;
    
    // 함수포인터 = &클래스이름::멤버함수 이름
    pf1 = &Point::Print;
    pf2 = &Point::PrintInt;
    
    // 객체 호출
    (pt.*pf1)(); // pt.Print()
    (pt.*pf1)(10); // pt.PrintInt(10)
    
    // 주소 호출
    (ptr->*pt2)(); // ptr->Print()
    (ptr->*pt2)(10); // ptr->PrintInt(10)
    
}

 

2-3. 클라이언트 코드와 서버 코드

  • 서버 코드 : 어떤 기능이나 서비스를 제공하는 코드 측
  • 클라이언트 코드 : 기능을 제공 받는 코드 측
// 서버
void Print()
{
    cout << "서버입니다" << endl;
}

// 클라이언트
int main()
{
    Print(); // 클라이언트가 서버를 Call한다.
}
  • 콜 : 클라이언트가 서버를 Call
  • 콜백 : 서버가 클라이언트 Call
// 서버
void Print()
{
    cout << "서버입니다" << endl;
    
    Client(); // 클라이언트 호출!
}

// 클라이언트
void Client()
{
    cout << "클라이언트입니다" << endl;
}

int main()
{
    Print(); // 서버 호출!
    
    return 0;
}
// 서버
void For_each(int *begin, int *end, void (*pf)(int))
{
    while(begin != end)
    {
    	pf(*begin++); // 클라이언트 함수 호출 (콜백)
    }
    
    cout << endl;
}

// 클라이언트
void Print1(int n)
{
    cout << n << ' ';
}

void Print2(int n)
{
    cout << n*10 << ' ';
}

void Print3(int n)
{
    cout << "정수 : " << n << endl;
}

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    
    // 클라이언트는 서버 함수 Foreach를 3번 호출한다.
    For_each(arr, arr+5, Print1);
    For_each(arr, arr+5, Print2);
    For_each(arr, arr+5, Print3);
    
    // 1 2 3 4 5
    // 10 20 30 40 50
    // 정수 : 1
    // ...
    // 정수 : 5
}

 

※ STL의 for_each 알고리즘

#include <algorithm> // for_each 사용을 위한 헤더파일

int main()
{
    for_each(arr, arr+5, Print();
}

 

'C++ STL > Part 01 C++ 문법' 카테고리의 다른 글

4장 템플릿  (0) 2021.06.22
3장 함수 객체  (0) 2021.06.22
1장 연산자 오버로딩  (0) 2021.06.17

댓글