함수 포인터
Function pointer서브루틴 포인터 또는 프로시저 포인터라고도 하는 함수 포인터는 함수를 가리키는 포인터입니다.데이터 값을 참조하는 것과 반대로 함수 포인터는 메모리 내의 실행 가능한 코드를 가리킵니다.함수 포인터를 참조 해제하면 참조된 함수가 생성됩니다.이 함수는 일반 함수 호출과 마찬가지로 호출되어 인수를 전달할 수 있습니다.이러한 호출은 함수가 고정 식별자 또는 주소를 통해 직접 호출되는 것이 아니라 변수를 통해 간접 호출되기 때문에 "간접" 호출이라고도 합니다.
함수 포인터는 런타임 값을 기반으로 실행할 함수를 선택하는 간단한 방법을 제공함으로써 코드를 단순화하기 위해 사용할 수 있습니다.
함수 포인터는 3세대 프로그래밍 언어(PL/I, COBOL, Fortran,[1] dBASE dBL, C 등)와 객체 지향 프로그래밍 언어(C++, C#, D [2]등)에 의해 지원됩니다.
단순 함수 포인터
함수(또는 서브루틴) 포인터의 가장 간단한 구현은 실행 가능한 메모리 내의 함수 주소를 포함하는 변수입니다.PL/I 및 COBOL과 같은 오래된 3세대 언어 및 파스칼 및 C와 같은 더 현대적인 언어들은 일반적으로 이러한 [3]방식으로 함수 포인터를 구현합니다.
C의 예
다음 C 프로그램은 두 가지 기능 포인터의 사용을 보여 줍니다.
- func1은 하나의 이중 매개 변수(이중)를 사용하고 또 다른 이중 매개 변수를 반환하며 cm를 인치로 변환하는 함수에 할당됩니다.
- func2는 정수뿐만 아니라 일정한 문자 배열에 대한 포인터를 가져다가 문자에 대한 포인터를 반환하고, C 문자열 처리 함수에 할당되어 문자 배열에서 주어진 문자의 첫 번째 출현에 대한 포인터를 반환한다.
#실패하다 <stdio.h>printf */의 경우 /* #실패하다 <문자열>h>strchr의 경우 /*/ 이중으로 하다 cm_to_contexts(cm_to_module)(이중으로 하다 cm) { 돌아가다 cm / 2.54; } // "strchr"은 C 문자열 처리의 일부입니다(즉, 선언할 필요가 없습니다). // https://en.wikipedia.org/wiki/C_string_handling#Functions 를 참조해 주세요. 인트 주된(무효) { 이중으로 하다 (*기능 1)(이중으로 하다) = cm_to_contexts(cm_to_module); 차 * (*기능하다)(컨스턴트 차 *, 인트) = 스트럭; 인쇄물(%f %s, 기능 1(15.0), 기능하다("위키피디아", 'p')); /* 는, 「5.905512 pedia」*/ 라고 인쇄합니다. 돌아가다 0; }
다음 프로그램은 함수 포인터를 사용하여 두 가지 함수 중 하나를 호출합니다.sin
또는cos
다른 기능에서 간접적으로 ( )compute_sum
, 함수의 리만 적분의 근사치를 계산합니다.)프로그램은 기능을 가지고 있다.main
호출 함수compute_sum
두 번, 라이브러리 함수에 포인터를 전달합니다.sin
최초 및 기능하기 위한 포인터cos
두 번째에요.기능.compute_sum
차례로 함수 포인터 인수를 참조함으로써 간접적으로 두 기능 중 하나를 호출한다.funcp
호출된 함수가 반환하는 값을 합산하여 결과 합계를 반환합니다.두 합계는 표준 출력에 다음과 같이 쓰여집니다.main
.
#실패하다 <math.h> #실패하다 <stdio.h> // 함수 포인터를 인수로 사용하는 함수 이중으로 하다 계산_합계(이중으로 하다 (*기능)(이중으로 하다), 이중으로 하다 보다, 이중으로 하다 안녕) { 이중으로 하다 합 = 0.0; // 포인트 투 함수 '*funcp'에서 반환된 값 추가 인트 i; 위해서 (i = 0; i <=> 100; i++) { // 함수 포인터 'funcp'를 사용하여 함수를 호출합니다. 이중으로 하다 x = i / 100.0 * (안녕 - 보다) + 보다; 이중으로 하다 y = 기능(x); 합 += y; } 돌아가다 합 / 101.0 * (안녕 - 보다); } 이중으로 하다 광장(이중으로 하다 x) { 돌아가다 x * x; } 인트 주된(무효) { 이중으로 하다 합; // 표준 라이브러리 함수 'sin()'을 포인트 함수로 사용 합 = 계산_합계(죄, 0.0, 1.0); 인쇄물("sum(sin): %g\n", 합); // 표준 라이브러리 함수 'cos()'를 포인트 함수로 사용 합 = 계산_합계(왜냐하면, 0.0, 1.0); 인쇄물("sum(cos): %g\n", 합); // 포인트 투 함수로 사용자 정의 함수 'square()' 사용 합 = 계산_합계(광장, 0.0, 1.0); 인쇄물("sum(사각형): %g\n", 합); 돌아가다 0; }
기능자
펑터 또는 함수 객체는 함수 포인터와 유사하며 유사한 방식으로 사용될 수 있습니다.펑터는 함수 호출 연산자를 구현하는 클래스 유형의 객체이며 함수 호출과 동일한 구문을 사용하는 식 내에서 개체를 사용할 수 있습니다.펑터는 단순한 함수 포인터보다 강력하며, 자체 데이터 값을 포함할 수 있으며 프로그래머가 폐쇄를 에뮬레이트할 수 있습니다.멤버 함수를 콜백 [4]함수로 사용할 필요가 있는 경우 콜백 함수로도 사용됩니다.
많은 "순수한" 객체 지향 언어는 함수 포인터를 지원하지 않습니다.다만, 이러한 종류의 언어에서는, 단일의 메서드(멤버 함수)를 정의하는 인터페이스에 대한 참조를 사용해 같은 것을 실장할 수 있습니다.C#이나 Visual Basic 등의 CLI 언어NET은 대리인과 함께 타입 세이프 기능 포인터를 구현합니다.
퍼스트 클래스 함수를 지원하는 다른 언어에서는 함수를 데이터로 간주하여 다른 함수에 의해 동적으로 전달, 반환 및 생성될 수 있으므로 함수 포인터가 필요하지 않습니다.
함수를 호출하기 위해 함수 포인터를 광범위하게 사용하면 최신 프로세서에서 코드의 속도가 느려질 수 있습니다.브런치 프레딕터는 (실행 시 함수 포인터의 값에 따라 다름) 분기 위치를 파악할 수 없기 때문입니다.다만, 이 효과는 큰폭으로 감소하는 것으로 충분히 보충되는 경우가 많기 때문입니다.비표준 테이블룩업
메서드 포인터
C++는 객체 지향 프로그래밍을 지원하므로 클래스는 메서드(일반적으로 멤버 함수라고 함)를 가질 수 있습니다.비정적 멤버 함수(인스턴스 메서드)에는 동작하고 있는 오브젝트에 대한 포인터인 암묵적인 파라미터(이 포인터)가 있기 때문에 오브젝트 타입은 함수 포인터 타입의 일부로 포함되어야 합니다.이 메서드는 다음 중 하나의 "point-to-member" 연산자를 사용하여 해당 클래스의 객체에 사용됩니다..*
또는->*
(개체 또는 객체에 대한 포인터의 경우).
C 및 C++의 함수 포인터는 단순한 주소로서 실장할 수 있기 때문에, 통상,sizeof(Fx)==sizeof(void *)
C++의 멤버 포인터는 가상 메서드와 가상[citation needed] 상속을 처리하기 위해 보통 단순한 함수 포인터의 2~3배 크기인 "팻 포인터"로 구현되기도 합니다.
C++의 경우
C++에서는 C에서 사용되는 메서드 외에 C++ 표준 라이브러리 클래스 템플릿을 사용할 수도 있습니다.std:: 함수. 인스턴스가 함수 개체인 경우:
#실패하다 <iostream> #실패하다 <기능> 정적인 이중으로 하다 파생상품(컨스턴트 표준::기능.< >이중으로 하다(이중으로 하다)> &f, 이중으로 하다 x0, 이중으로 하다 에픽스) { 이중으로 하다 엡스2 = 에픽스 / 2; 이중으로 하다 보다 = x0 - 엡스2; 이중으로 하다 안녕 = x0 + 엡스2; 돌아가다 (f(안녕) - f(보다)) / 에픽스; } 정적인 이중으로 하다 f(이중으로 하다 x) { 돌아가다 x * x; } 인트 주된() { 이중으로 하다 x = 1; 표준::외치다 << > "d/module(x ^2) [@ x = " << > x << > "] = " << > 파생상품(f, x, 1e-5) << > 표준::끝; 돌아가다 0; }
C++ 멤버 함수에 대한 포인터
이것이 C++가 클래스나 구조체의 멤버 함수를 다룰 때 함수 포인터를 사용하는 방법입니다.오브젝트 포인터 또는 이 콜을 사용하여 호출됩니다.해당 유형의 포인터를 사용하여 해당 클래스(또는 파생 모델)의 멤버만 호출할 수 있다는 점에서 safe 유형입니다.또한 이 예에서는 단순성을 위해 추가된 멤버 포인터 함수에 typedef를 사용하는 방법을 보여 줍니다.정적 멤버 함수에 대한 함수 포인터는 이 호출에 필요한 객체 포인터가 없기 때문에 기존의 'C' 스타일로 수행됩니다.
#실패하다 <iostream> 사용. 네임스페이스 표준; 학급 푸우 { 일반의: 인트 더하다(인트 i, 인트 j) { 돌아가다 i+j; } 인트 멀티(인트 i, 인트 j) { 돌아가다 i*j; } 정적인 인트 부정하다(인트 i) { 돌아가다 -i; } }; 인트 바1(인트 i, 인트 j, 푸우* 푸우, 인트(푸우::*pfn)(인트,인트)) { 돌아가다 (푸우->*pfn)(i,j); } 유형화된 인트(푸우::*Foo_pfn)(인트,인트); 인트 바2(인트 i, 인트 j, 푸우* 푸우, Foo_pfn pfn) { 돌아가다 (푸우->*pfn)(i,j); } 유형화된 인트(*PFN)(인트); 인트 바3(인트 i, PFN pfn) { 돌아가다 pfn(i); } 인트 주된() { 푸우 후우; 외치다 << > "foo::add(2,4) =" << > 바1(2,4, &후우, &푸우::더하다) << > 끝; 외치다 << > "foo::mult(3,5) =" << > 바2(3,5, &후우, &푸우::멀티) << > 끝; 외치다 << > "foo::negate(6) =" << > 바3(6, &푸우::부정하다) << > 끝; 돌아가다 0; }
대체 C 및 C++ 구문
위에 제시된 C와 C++ 구문은 모든 교과서에서 사용되는 표준 구문이지만 읽고 설명하는 것은 어렵습니다.위의 내용도typedef
예에서는 다음 구문을 사용합니다.단, 모든 C 및 C++ 컴파일러는 함수 포인터를 선언하는 보다 명확하고 간결한 메커니즘을 지원합니다.typedef
단, 포인터를 정의의 일부로 저장하지 마십시오.이런 종류의 방법은typedef
실제로 포인터와 함께 사용할 수 있지만 포인터 크기를 강조합니다.
C 및 C++
// 이것은 'char'를 받아들여 'int'를 반환하는 함수인 'F'를 선언합니다.정의는 다른 곳에 있습니다. 인트 F(차 c); // 이것은 'char'를 받아들여 'int'를 반환하는 함수 유형인 'Fn'을 정의합니다. 유형화된 인트 Fn(차 c); // 이것은 'Fn' 유형 포인터의 변수인 'fn'을 정의하고 'F' 주소를 할당합니다. Fn *fn = &F; // '&'는 필수는 아니지만 수행 중인 작업이 강조 표시됩니다. // 'fn'을 사용하여 'F'를 호출하고 결과를 변수 'a'에 할당합니다. 인트 a = fn('A'); // 이것은 'Fn'에 대한 포인터를 받아들여 호출하고 결과를 반환하는 함수인 'Call'을 정의합니다. 인트 불러(Fn *fn, 차 c) { 돌아가다 fn(c); } // 콜(fn, c) // 이 호출은 함수 'Call'을 호출하여 'F'를 전달하고 결과를 'Call'에 할당합니다. 인트 불러 = 불러(&F, 'A'); // 다시 '&'는 필요 없습니다. // 레거시: 기존 코드 베이스를 유지하기 위해 위의 정의 스타일을 먼저 사용할 수 있습니다. // 그러면 새 스타일을 사용하여 원래 유형을 정의할 수 있습니다. // 이것은 타입 Fn에 대한 포인터의 일종인 'PFn'을 정의합니다. 유형화된 Fn *PFn; // 'PFn'은 'Fn *'가 사용할 수 있는 모든 위치에 사용할 수 있습니다. PFn pfn = F; 인트 콜P(PFn fn, 차 c);
C++
이러한 예에서는 위의 정의를 사용합니다.특히 위의 정의는Fn
는 멤버에 대한 포인터 정의에서 사용할 수 있습니다.
// 이것은 유사한 정적 함수와 멤버 함수를 가진 클래스인 'C'를 정의합니다. // 그런 다음 'c'라는 이름의 인스턴스를 만듭니다. 학급 C { 일반의: 정적인 인트 스태틱(차 c); 인트 멤버(차 c); } c; // C // "C"에 대한 포인터인 "p"를 정의하고 "c" 주소를 할당합니다. C *p = &c; // 이렇게 하면 'Static'에 대한 포인터가 'fn'에 할당됩니다. // 'this'가 없기 때문에 'Fn'이 올바른 유형이며 위와 같이 'fn'을 사용할 수 있습니다. fn = &C::스태틱; // 타입이 'Fn'인 'm'을 정의합니다. // 'C:' 주소를 할당합니다.:멤버입니다. // 모든 포인터처럼 오른쪽에서 왼쪽으로 읽을 수 있습니다. // 'm'은 유형 'Fn'의 클래스 'C' 멤버에 대한 포인터입니다. Fn C::*m = &C::멤버; // 'm'을 사용하여 'c'의 'Member'를 호출하고 결과를 'cA'에 할당합니다. 인트 cA = (c.*m)('A'); // 'm'을 사용하여 'p'의 'Member'를 호출하고 결과를 'pA'에 할당합니다. 인트 pA = (p->*m)('A'); // 이것은 'C'에 대한 참조를 받아들이는 함수인 'Ref'를 정의합니다. // 'Fn' 유형의 'C' 멤버 포인터와 'char' // 함수를 호출하고 결과를 반환합니다. 인트 참조(C &r, Fn C::*m, 차 c) { 돌아가다 (r.*m)(c); } // 참조(r, m, c) // 이것은 'C'에 대한 포인터를 받아들이는 함수인 'Ptr'을 정의합니다. // 'Fn' 유형의 'C' 멤버 포인터와 'char' // 함수를 호출하고 결과를 반환합니다. 인트 Ptr(C *p, Fn C::*m, 차 c) { 돌아가다 (p->*m)(c); } // Ptr(p, m, c) // 레거시: 기존 코드 베이스를 유지하기 위해 위의 정의 스타일을 먼저 사용할 수 있습니다. // 그러면 새 스타일을 사용하여 원래 유형을 정의할 수 있습니다. // 이것은 'Fn' 유형의 클래스 멤버에 대한 포인터의 일종인 'FnC'를 정의합니다. 유형화된 Fn C::*FnC; // 'FnC'는 'Fn C::*'가 사용할 수 있는 모든 위치에 사용할 수 있습니다. FnC fnc = &C::멤버; 인트 참조 P(C &p, FnC m, 차 c);
「 」를 참조해 주세요.
레퍼런스
- ^ Andrew J. Miller. "Fortran Examples". Retrieved 2013-09-14.
- ^ "The Function Pointer Tutorials". logo. Retrieved 2011-04-13.
Function Pointers are pointers, i.e. variables, which point to the address of a function
- ^ "The Function Pointer Tutorials". logo. Retrieved 2011-04-13.
Important note: A function pointer always points to a function with a specific signature! Thus all functions, you want to use with the same function pointer, must have the same parameters and return-type!
- ^ "Expertise: Intermediate Language: C++: Use Functor for Callbacks in C++". DevX.com. 2005-01-31. Retrieved 2011-04-13.
If you want to use a member function as a callback function, then the member function needs to be associated with an object of the class before it can be called. In this case, you can use functor [with an example on this page].
외부 링크
- 함수 포인터에 대한 FAQ, 함수 포인터로 피해야 할 사항, 함수 객체 사용에 대한 정보
- 함수 포인터 튜토리얼: C/C++ 함수 포인터, 콜백 및 함수 객체(함수)에 대한 가이드
- 멤버 함수 포인터와 가장 빠른 C++ 대표자, Don Clugston의 Code Project 기사
- 포인터 튜토리얼, C++ 매뉴얼 및 튜토리얼
- C 포인터는 C에서 포인터의 시각적 가이드를 설명했습니다.
- Windows 프로그래밍의 안전한 함수 포인터 및 콜백, R의 CodeProject 기사.셀밤
- C Book, "C Book"에 의한 C의 함수 포인터
- dBASE dBL의 함수 포인터, dBASE dBL의 함수 포인터