함수 포인터의 포인트는 무엇입니까?
함수 포인터의 유틸리티를 확인하는 데 문제가 있습니다.경우에 따라서는 도움이 될 수도 있다고 생각합니다만, 기능 포인터를 사용하는 것이 좋거나 피할 수 없는 경우는 생각할 수 없습니다.
(C 또는 C++에서) 함수 포인터의 좋은 사용 예를 들어 주시겠습니까?
대부분의 예는 콜백으로 요약됩니다.함수를 호출합니다.f()
함수의 g()
, , , , 입니다.f()
®g()
특정 작업에 사용됩니다.f()
의 h()
「」을 합니다.f()
h()
★★★★★★ 。
기본적으로 함수를 파라미터화하는 방법은 다음과 같습니다.동작의 일부는 하드 코드화되어 있지 않습니다.f()
콜백 함수로 변환됩니다.는, 「」를 할 수 .f()
다른 콜백 함수를 전달함으로써 동작이 달라집니다.은 고전 a a a a 。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]
위의 모든 것에 동의하고, 게다가...런타임에 dll을 동적으로 로드하는 경우 함수를 호출하기 위한 함수 포인터가 필요합니다.
다른 관점, 여기에 제시된 다른 좋은 답변도 있습니다.
C에서는 함수 포인터만 사용하고 (직접) 함수는 사용하지 않습니다.
함수는 쓰지만 함수는 조작할 수 없어요사용할 수 있는 함수의 런타임 표현은 없습니다.'함수'라고 부르지도 못하잖아글을 쓸 때:
my_function(my_arg);
은 '' 입니다my_function
지정된 인수로 포인터를 지정합니다.함수 포인터를 통해 전화를 걸고 있습니다.이 함수 포인터의 감쇠는 다음 명령어가 이전 함수 호출과 동등함을 의미합니다.
(&my_function)(my_arg);
(*my_function)(my_arg);
(**my_function)(my_arg);
(&**my_function)(my_arg);
(***my_function)(my_arg);
등등(@LuuVinhPuc님 감사합니다).
이미 함수 포인터를 값으로 사용하고 있습니다.이러한 값에 대한 변수를 사용하는 것은 당연합니다.다른 모든 용도는 다음과 같습니다.다형성/커스터마이제이션(qsort 등), 콜백, 점프 테이블 등입니다.
++가 있는 에 조금 더 복잡합니다.operator()
「」, 「」, 「」도 입니다.std::function
수업, 하지만 원칙은 여전히 거의 똑같습니다.
함수 포인터 사용
사용자 입력에 따라 동적으로 함수를 호출합니다.이 경우 문자열과 함수 포인터의 맵을 만듭니다.
#include<iostream>
#include<map>
using namespace std;
//typedef map<string, int (*)(int x, int y) > funMap;
#define funMap map<string, int (*)(int, int)>
funMap objFunMap;
int Add(int x, int y)
{
return x+y;
}
int Sub(int x, int y)
{
return x-y;
}
int Multi(int x, int y)
{
return x*y;
}
void initializeFunc()
{
objFunMap["Add"]=Add;
objFunMap["Sub"]=Sub;
objFunMap["Multi"]=Multi;
}
int main()
{
initializeFunc();
while(1)
{
string func;
cout<<"Enter your choice( 1. Add 2. Sub 3. Multi) : ";
int no, a, b;
cin>>no;
if(no==1)
func = "Add";
else if(no==2)
func = "Sub";
else if(no==3)
func = "Multi";
else
break;
cout<<"\nEnter 2 no :";
cin>>a>>b;
//function is called using function pointer based on user input
//If user input is 2, and a=10, b=3 then below line will expand as "objFuncMap["Sub"](10, 3)"
int ret = objFunMap[func](a, b);
cout<<ret<<endl;
}
return 0;
}
이렇게 해서 실제 회사 코드에 함수 포인터를 사용했습니다.이 방법을 사용하여 함수의 'n' 번호를 입력하고 호출할 수 있습니다.
출력:
선택지(1)를 입력합니다.2를 더해라. Sub 3.멀티): 12 no:2 4 를 입력합니다.6선택지(1)를 입력합니다.2를 더해라. Sub 3.멀티): 22 no : 10 3 을 입력합니다.7선택지(1)를 입력합니다.2를 더해라. Sub 3.멀티): 32 no: 3 6을 입력합니다.18
제가 주로 사용하는 것은 CALLBACKs입니다: 나중에 호출하기 위해 함수에 대한 정보를 저장해야 할 때입니다.
폭탄을지 후에 한다.explode()
★★★★★★★★★★★★★★★★★★」
이제 2가지 방법으로 하는 겁니다.한가지 방법은 화면에 만약 그들은 주요 루프에 급증할 지를 보는 것은 모든 폭탄"조사"것이다.
foreach bomb in game
if bomb.boomtime()
bomb.explode()
또 다른 방법은 당신의 시계 시스템에 콜백을 첨부하는 것입니다.언제 폭탄 심어질 때 시간은 맞다 그것 bomb.explode()를 호출할 콜백을 더한다.
// user placed a bomb
Bomb* bomb = new Bomb()
make callback( function=bomb.explode, time=5 seconds ) ;
// IN the main loop:
foreach callback in callbacks
if callback.timeToRun
callback.function()
서 ★★★★callback.function()
될 수 있다고 되는 어떤 함수, 우리가 보고 있는 함수 포인터입니다.
나는 광범위하게 1-byte opcode가 마이크로 프로세서들을 흉내내는 것에 함수 포인터를 사용한다.256함수 포인터의 배열이 자연적인 길이 이런 절차를 구현하다.
나는 여기를 다소 포괄적인 목록을 제공하여 노력할 거야.
Callbacks:사용자 공급 코드와 일부(도서관)기능 사용자 지정합니다.프라임의 예는
qsort()
시 등) 스레드 시 처리(클릭 시 콜백)에도이 됩니다.pthread_create()
를 참조해 주세요.다형성:C++ 클래스의 vtable은 함수 포인터의 테이블에 불과합니다.또한 C 프로그램은 일부 개체에 대해 vtable을 제공하도록 선택할 수도 있습니다.
struct Base; struct Base_vtable { void (*destruct)(struct Base* me); }; struct Base { struct Base_vtable* vtable; }; struct Derived; struct Derived_vtable { struct Base_vtable; void (*frobnicate)(struct Derived* me); }; struct Derived { struct Base; int bar, baz; }
★★★★★★★★★★★★★★★★★★★의 제작자
Derived
ㄴㄴㄴㄴ가요?vtable
destruct
★★★★★★★★★★★★★★★★★」frobnicate
「」를 하기 위해서struct Base*
전화만 하면 된다base->vtable->destruct(base)
파생 「Destructor합니다.base
실제로 가리키고 있습니다.함수 포인터가 없으면 다형성은 다음과 같은 스위치 구조를 사용하여 코드화할 필요가 있습니다.
switch(me->type) { case TYPE_BASE: base_implementation(); break; case TYPE_DERIVED1: derived1_implementation(); break; case TYPE_DERIVED2: derived2_implementation(); break; case TYPE_DERIVED3: derived3_implementation(); break; }
이것은 다소 다루기 어려워지고 오히려 빠르게.
동적으로 로드된 코드:프로그램이 모듈을 메모리에 로드하고 코드를 호출하려고 할 때 함수 포인터를 통과해야 합니다.
지금까지 본 함수 포인터의 사용법은 크게 세 가지 종류 중 하나로 분류됩니다.
"입니다.qsort()
을 사용하다사용자가 생각할 수 있는 모든 데이터 구조에 대해 보편적이기 위해서는 정렬 가능한 데이터에 대한 몇 개의 보이드 포인터와 이들 데이터 구조의 두 요소를 비교하는 방법을 아는 함수에 대한 포인터가 필요합니다.이를 통해 작업에 대한 선택 기능을 만들 수 있으며, 실제로 실행 시 비교 기능을 선택할 수도 있습니다(예: 오름차순 또는 내림차순 정렬).
나는 여기의 흐름을 거스른다.
C에서는 OO가 없기 때문에 커스터마이즈를 구현하는 유일한 방법은 함수 포인터입니다.
C++에서는 동일한 결과에 대해 함수 포인터 또는 펑터(함수 객체)를 사용할 수 있습니다.
펑터는 오브젝트 특성상 원시 함수 포인터보다 많은 이점이 있습니다.
- 여러 의 과부하가 할 수 .
operator()
- 기존 변수에 대한 상태/참조를 가질 수 있습니다.
- 수 .
lambda
★★★★★★★★★★★★★★★★★」bind
)
저는 개인적으로 함수 포인터보다 함수 포인터를 선호합니다(보일러플레이트 코드에도 불구하고). 함수 포인터의 구문은 (함수 포인터 튜토리얼에서) 쉽게 퍼질 수 있기 때문입니다.
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뿐입니다.스피릿. 그들은 구문을 완전히 악용해서 임의의 수의 매개 변수를 하나의 템플릿 매개 변수로 전달합니다.
typedef SpecialClass<float(float,float)> class_type;
그러나 바리에이딕 템플릿과 람다가 코앞에 있기 때문에 순수 C++ 코드의 함수 포인터를 오래 사용할 수 있을지 모르겠습니다.
예:
- 맞춤 정렬/검색
- 다양한 패턴(전략, 관찰자 등)
- 콜백
Rich가 위에서 말한 것처럼 Windows의 함수 포인터는 함수를 저장하는 주소를 참조하는 것이 매우 일반적입니다.
C language
DLL 메모리에 DLL 사용).LoadLibrary
되어 있는 포인터를 주소를 (DLL 사용GetProcAddress
를 참조해 주세요.
참고 자료:
OO언어의 경우, 백그라운드에서 다형 콜을 실시합니다(C도 어느 시점까지는 유효하다고 생각합니다).
또한 런타임에 다른 기능(foo)에 다른 동작을 주입하는 데 매우 유용합니다.그러면 foo 함수가 고차 함수가 됩니다.유연성 외에도 foo 코드를 읽기 쉽게 만들 수 있습니다. 왜냐하면 foo 코드를 사용하면 "if-else"라는 여분의 논리를 끌어낼 수 있기 때문입니다.
Python에서 발전기, 클로저 등 많은 유용한 것들을 사용할 수 있습니다.
C에서는 일반적으로 qsort 함수가 사용되며, 여기서 네 번째 파라미터는 정렬 내에서 순서를 수행하기 위해 사용하는 함수에 대한 포인터입니다.C++에서는, 이러한 것에 펑터(함수처럼 보이는 오브젝트)를 사용하는 경향이 있습니다.
저는 최근에 추상화 레이어를 만들기 위해 함수 포인터를 사용했습니다.
임베디드 시스템에서 실행되는 순수 C로 작성된 프로그램이 있습니다.여러 하드웨어 변형을 지원합니다.실행하고 있는 하드웨어에 따라서는, 다른 버전의 함수를 호출할 필요가 있습니다.
초기화 시 프로그램은 어떤 하드웨어에서 실행되고 있는지 파악하여 함수 포인터를 채웁니다.프로그램의 모든 상위 레벨 루틴은 포인터에 의해 참조되는 함수를 호출합니다.상위 레벨의 루틴을 건드리지 않고 새로운 하드웨어 모델에 대한 지원을 추가할 수 있습니다.
이전에는 적절한 기능 버전을 선택하기 위해 스위치/케이스 문을 사용했지만, 프로그램이 점점 더 많은 하드웨어 변형을 지원하도록 성장함에 따라 이는 실용적이지 않게 되었습니다.모든 곳에 사례 진술서를 추가해야 했습니다.
어떤 기능을 사용할지 알기 위해 중간 기능층을 시험해 보았지만 별 도움이 되지 않았습니다.새로운 변종을 추가할 때마다 여러 곳에서 사례 설명을 업데이트해야 했습니다.함수 포인터에서는 초기화 기능만 변경하면 됩니다.
C에서 함수 포인터를 사용하여 프로그래밍할 인터페이스를 만들 수 있습니다.런타임에 필요한 특정 기능에 따라 다른 구현을 함수 포인터에 할당할 수 있습니다.
함수 포인터의 한 가지 용도는 함수가 호출되는 코드를 변경하지 않는 경우입니다(따라서 콜은 조건부일 수 있으며 다른 조건에서는 다른 종류의 처리를 수행해야 합니다.여기서 함수 포인터는 함수를 호출하는 위치에서 코드를 수정할 필요가 없기 때문에 매우 편리합니다.적절한 인수를 사용하여 함수 포인터를 사용하여 함수를 호출합니다.함수 포인터는 조건부로 다른 기능을 가리키도록 할 수 있습니다(이는 초기화 단계 중 어딘가에서 수행할 수 있습니다).또한 위의 모델은 호출되는 코드를 수정할 수 없는 경우(라이브러리 API를 수정할 수 없는 경우) 매우 유용합니다.API는 함수 포인터를 사용하여 적절한 사용자 정의 함수를 호출합니다.
언급URL : https://stackoverflow.com/questions/2592137/what-is-the-point-of-function-pointers
'programing' 카테고리의 다른 글
Java에서 패키지를 문서화하는 방법 (0) | 2022.08.14 |
---|---|
Vue-Router의 내비게이션가드에서 뒤로 버튼 검출 (0) | 2022.08.14 |
왜 '?'와 '\?'는 C에서 같은 출력을 출력합니까? (0) | 2022.08.14 |
실행 파일에 사용된 정적 라이브러리 목록 가져오기 (0) | 2022.08.14 |
외부 스크립트가 Vue.js에 로드될 때까지 실행을 연기합니다. (0) | 2022.08.14 |