[c++] 함수 포인터의 요점은 무엇입니까?

함수 포인터의 유용성을 보는 데 문제가 있습니다. 나는 그것이 어떤 경우에 유용 할 것이라고 생각하지만 (결국 존재한다) 함수 포인터를 사용하는 것이 더 낫거나 피할 수없는 경우를 생각할 수 없다.

함수 포인터 (C 또는 C ++)를 잘 사용하는 몇 가지 예를 들어 주시겠습니까?



답변

대부분의 예는 졸이다 콜백 : 당신은 함수를 호출 f()하는 다른 함수의 주소를 전달 g()하고, f()호출 g()일부 특정 작업에 대한합니다. 대신 f()주소 를 전달 하면 h()대신 f()콜백 h()합니다.

기본적으로 이것은 함수 를 매개 변수화 하는 방법 입니다. 동작의 일부는으로 하드 코딩되지 않고 f()콜백 함수로 코딩됩니다 . 호출자는 f()다른 콜백 함수를 전달 하여 다르게 행동 할 수 있습니다 . 클래식은 qsort()C 표준 라이브러리에서 가져온 것으로, 정렬 기준을 비교 함수에 대한 포인터로 사용합니다.

C ++에서 이는 종종 함수 객체 (펑 터라 고도 함)를 사용하여 수행됩니다 . 이들은 함수 호출 연산자를 오버로드하는 객체이므로 마치 함수 인 것처럼 호출 할 수 있습니다. 예:

class functor {
  public:
     void operator()(int i) {std::cout << "the answer is: " << i << '\n';}
};

functor f;
f(42);

이 개념은 함수 포인터와 달리 함수 객체가 알고리즘뿐 아니라 데이터도 전달할 수 있다는 것입니다.

class functor {
  public:
     functor(const std::string& prompt) : prompt_(prompt) {}
     void operator()(int i) {std::cout << prompt_ << i << '\n';}
  private:
     std::string prompt_;
};

functor f("the answer is: ");
f(42);

또 다른 장점은 함수 포인터를 통한 호출보다 함수 객체에 대한 호출을 인라인하는 것이 더 쉽다는 것입니다. 이것이 C ++에서 정렬하는 것이 때때로 C에서 정렬하는 것보다 빠른 이유입니다.


답변

글쎄, 나는 일반적으로 점프 테이블 에서 (전문적으로) 사용합니다 ( 이 StackOverflow 질문 참조 ).

점프 테이블은 유한 상태 머신 에서 일반적으로 (배타적이지는 않음) 사용되어 데이터 기반을 만듭니다. 중첩 된 스위치 / 케이스 대신

  switch (state)
     case A:
       switch (event):
         case e1: ....
         case e2: ....
     case B:
       switch (event):
         case e3: ....
         case e1: ....

함수 포인터의 2d 배열을 만들고 handleEvent[state][event]


답변

예 :

  1. 맞춤 정렬 / 검색
  2. 다양한 패턴 (예 : 전략, 관찰자)
  3. 콜백


답변

함수 포인터의 유용성에 대한 “고전적인”예 qsort()는 빠른 정렬을 구현하는 C 라이브러리 함수입니다. 사용자가 생각 해낼 수있는 모든 데이터 구조에 대해 보편적이되기 위해서는 정렬 가능한 데이터에 대한 두 개의 void 포인터와 이러한 데이터 구조의 두 요소를 비교하는 방법을 알고있는 함수에 대한 포인터가 필요합니다. 이를 통해 작업에 대해 선택한 기능을 생성 할 수 있으며, 실제로 런타임에 비교 기능을 선택할 수도 있습니다 (예 : 오름차순 또는 내림차순 정렬).


답변

위의 모든 사항에 동의하고 .. 런타임에 DLL을 동적으로로드 할 때 함수를 호출하기위한 함수 포인터가 필요합니다.


답변

나는 여기서 현재에 반대 할 것입니다.

C에서 함수 포인터는 사용자 정의를 구현하는 유일한 방법입니다. OO가 없기 때문입니다.

C ++에서는 동일한 결과에 대해 함수 포인터 또는 펑터 (함수 객체)를 사용할 수 있습니다.

펑 터는 객체 특성으로 인해 원시 함수 포인터에 비해 다음과 같은 여러 장점이 있습니다.

  • 그들은 몇 가지 과부하를 나타낼 수 있습니다. operator()
  • 기존 변수에 대한 상태 / 참조를 가질 수 있습니다.
  • 즉석에서 만들 수 있습니다 ( lambdabind).

저는 개인적으로 함수 포인터보다 함수 포인터를 선호합니다 (상용구 코드에도 불구하고), 주로 함수 포인터 구문이 쉽게 어려울 수 있기 때문입니다 ( Function Pointer Tutorial에서 ).

typedef float(*pt2Func)(float, float);
  // defines a symbol pt2Func, pointer to a (float, float) -> float function

typedef int (TMyClass::*pt2Member)(float, char, char);
  // defines a symbol pt2Member, pointer to a (float, char, char) -> int function
  // belonging to the class TMyClass

펑터가 사용할 수없는 곳에서 함수 포인터가 사용되는 것을 본 것은 Boost.Spirit뿐이었습니다. 그들은 임의의 수의 매개 변수를 단일 템플릿 매개 변수로 전달하기 위해 구문을 완전히 남용했습니다.

 typedef SpecialClass<float(float,float)> class_type;

그러나 가변 템플릿과 람다가 모퉁이에 있기 때문에 우리가 오랫동안 순수한 C ++ 코드에서 함수 포인터를 사용할지 확신 할 수 없습니다.


답변

C에서 고전적인 용도는 qsort 함수입니다 . 여기서 네 번째 매개 변수는 정렬 내에서 정렬을 수행하는 데 사용할 함수에 대한 포인터입니다. C ++에서는 이런 종류의 일에 펑터 (함수처럼 보이는 객체)를 사용하는 경향이 있습니다.