c++ c# delegate - C ++의 콜백 함수





4 Answers

또한 콜백을 수행하는 C 방식이 있습니다 : 함수 포인터

//Define a type for the callback signature,
//it is not necessary, but makes life easier

//Function pointer called CallbackType that takes a float
//and returns an int
typedef int (*CallbackType)(float);  


void DoWork(CallbackType callback)
{
  float variable = 0.0f;

  //Do calculations

  //Call the callback with the variable, and retrieve the
  //result
  int result = callback(variable);

  //Do something with the result
}

int SomeCallback(float variable)
{
  int result;

  //Interpret variable

  return result;
}

int main(int argc, char ** argv)
{
  //Pass in SomeCallback to the DoWork
  DoWork(&SomeCallback);
}

이제 클래스 메소드를 콜백으로 전달하려는 경우 해당 함수 포인터에 대한 선언은보다 복잡한 선언을 갖습니다. 예를 들면 다음과 같습니다.

//Declaration:
typedef int (ClassName::*CallbackType)(float);

//This method performs work using an object instance
void DoWorkObject(CallbackType callback)
{
  //Class instance to invoke it through
  ClassName objectInstance;

  //Invocation
  int result = (objectInstance.*callback)(1.0f);
}

//This method performs work using an object pointer
void DoWorkPointer(CallbackType callback)
{
  //Class pointer to invoke it through
  ClassName * pointerInstance;

  //Invocation
  int result = (pointerInstance->*callback)(1.0f);
}

int main(int argc, char ** argv)
{
  //Pass in SomeCallback to the DoWork
  DoWorkObject(&ClassName::Method);
  DoWorkPointer(&ClassName::Method);
}
목적 callback 예제

C ++에서는 언제, 어떻게 콜백 함수를 사용합니까?

편집하다:
나는 콜백 함수를 작성하는 간단한 예제를보고 싶다.




콜백 함수 는 루틴으로 전달 된 메소드이며, 전달 된 루틴에 의해 어느 시점에서 호출됩니다.

이것은 재사용 가능한 소프트웨어를 만드는 데 매우 유용합니다. 예를 들어 많은 운영 체제 API (예 : Windows API)는 콜백을 많이 사용합니다.

예를 들어 폴더에있는 파일을 사용하여 작업하고 싶다면 자신의 루틴으로 API 함수를 호출 할 수 있으며 루틴은 지정된 폴더에서 파일 당 한 번 실행됩니다. 이렇게하면 API를 매우 유연하게 사용할 수 있습니다.




C ++에서 콜백 함수에 대한 명시 적 개념은 없습니다. 콜백 메커니즘은 종종 함수 포인터, 펑터 객체 또는 콜백 객체를 통해 구현됩니다. 프로그래머는 명시 적으로 콜백 기능을 설계하고 구현해야합니다.

의견을 기반으로 수정 :

이 답변이받은 부정적인 피드백에도 불구하고 틀린 것은 아닙니다. 나는 내가 어디에서 왔는지 설명하는 더 나은 일을하려고 노력할 것이다.

C 및 C ++에는 콜백 함수를 구현하는 데 필요한 모든 것이 있습니다. 콜백 함수를 구현하는 가장 일반적이고 간단한 방법은 함수 포인터를 함수 인수로 전달하는 것입니다.

그러나 콜백 함수와 함수 포인터는 동의어가 아닙니다. 함수 포인터는 언어 메커니즘이지만 콜백 함수는 의미 개념입니다. 함수 포인터는 콜백 함수를 구현하는 유일한 방법이 아닙니다. 또한 펑터 (functor)를 사용할 수도 있고 다양한 가든 가상 함수를 사용할 수도 있습니다. 함수 호출을 콜백으로 만드는 것은 함수를 식별하고 호출하는 데 사용되는 메커니즘이 아니라 호출의 컨텍스트와 의미입니다. 무언가를 콜백 함수라고하면 콜 함수와 호출되는 특정 함수 사이의 정상적인 분리보다 더 큰 의미가 있습니다. 호출자와 호출 수신자 사이의 느슨한 개념 결합으로 호출자는 호출 대상을 명시 적으로 제어합니다. 느슨한 개념 결합과 호출자 기반 함수 선택이라는 퍼지 개념은 함수 포인터가 아닌 콜백 함수를 만듭니다.

예를 들어, IFormatProvider 대한 .NET 설명서에 따르면 "GetFormat은 콜백 메서드입니다."라는 평범한 인터페이스 메서드 일지라도. 나는 모든 가상 메소드 호출이 콜백 함수라고 주장 할 사람은 없을 것이라고 생각한다. GetFormat을 콜백 메서드로 만드는 것은 전달 또는 호출 방법의 메커니즘이 아니라 호출자가 어떤 개체의 GetFormat 메서드를 호출 할 것인지를 결정하는 기능입니다.

일부 언어에는 일반적으로 이벤트 및 이벤트 처리와 관련된 명시 적 콜백 의미가있는 기능이 포함됩니다. 예를 들어, C #은 콜백 개념을 중심으로 명시 적으로 디자인 된 구문 및 의미를 갖는 이벤트 유형을가집니다. Visual Basic에는 대리자 또는 함수 포인터 개념을 추상화하는 동안 콜백 함수로 명시 적으로 선언하는 Handles 절이 있습니다. 이러한 경우 콜백의 의미 개념은 언어 자체에 통합됩니다.

반면에 C와 C ++은 콜백 함수의 의미 개념 을 거의 명시 적으로 포함하지 않습니다. 메커니즘은 거기에 있으며 통합 된 의미는 없습니다. 콜백 함수를 잘 구현할 수는 있지만 Qt가 신호와 슬롯에서 했던 것과 같이 C ++이 제공하는 것 위에 빌드해야하는 명시적인 콜백 의미를 포함하는보다 정교한 것을 얻으려면 더욱 그렇습니다 .

간단히 말해 C ++에는 콜백을 구현하는 데 필요한 기능이 있습니다. 종종 함수 포인터를 사용하는 것이 쉽고 간단합니다. 여기에는 raise , emit , Handles , event + = 등과 같은 콜백에만 해당하는 의미가있는 키워드와 기능이 있습니다. 이러한 유형의 언어를 사용하는 언어를 사용하는 경우 C ++의 네이티브 콜백 지원 중성화 될 것입니다.




콜백 함수가 다른 함수로 넘겨지고 어떤 시점에서이 함수가 호출되는 위의 정의를 참조하십시오.

C ++에서는 콜백 함수가 클래스 메소드를 호출하는 것이 바람직합니다. 이렇게하면 회원 데이터에 액세스 할 수 있습니다. 콜백을 정의하는 C 방식을 사용하는 경우 정적 멤버 함수를 가리켜 야합니다. 이것은 그리 바람직하지 않습니다.

다음은 C ++에서 콜백을 사용하는 방법입니다. 4 파일을 가정하십시오. 각 클래스에 대한 .CPP / .H 파일 쌍. 클래스 C1은 콜백 할 메소드가있는 클래스입니다. C2는 C1의 메소드를 다시 호출합니다. 이 예제에서 콜백 함수는 독자를 위해 추가 한 1 개의 매개 변수를 사용합니다. 이 예제에는 인스턴스화되고 사용되는 오브젝트가 표시되지 않습니다. 이 구현의 한 가지 유스 케이스는 데이터를 읽고 임시 공간에 저장하는 클래스와 포스트가 데이터를 처리하는 클래스가있는 경우입니다. 콜백 함수를 사용하면 읽은 모든 데이터 행에 대해 콜백이 처리 할 수 ​​있습니다. 이 기술은 필요한 임시 공간의 오버 헤드를 제거합니다. 후 처리해야하는 대량의 데이터를 반환하는 SQL 쿼리에 특히 유용합니다.

/////////////////////////////////////////////////////////////////////
// C1 H file

class C1
{
    public:
    C1() {};
    ~C1() {};
    void CALLBACK F1(int i);
};

/////////////////////////////////////////////////////////////////////
// C1 CPP file

void CALLBACK C1::F1(int i)
{
// Do stuff with C1, its methods and data, and even do stuff with the passed in parameter
}

/////////////////////////////////////////////////////////////////////
// C2 H File

class C1; // Forward declaration

class C2
{
    typedef void (CALLBACK C1::* pfnCallBack)(int i);
public:
    C2() {};
    ~C2() {};

    void Fn(C1 * pThat,pfnCallBack pFn);
};

/////////////////////////////////////////////////////////////////////
// C2 CPP File

void C2::Fn(C1 * pThat,pfnCallBack pFn)
{
    // Call a non-static method in C1
    int i = 1;
    (pThat->*pFn)(i);
}



Related