How do you implement the callback method example in C++

  • 2020-05-30 20:50:11
  • OfStack

preface

Callbacks are implemented using the class syntax in C++ (of course, the old C function pointer callback is also supported)

For example, someone offers a class library called AfCopyFile, which provides the ability to copy files and notify the user of the current progress.


int DoCopy(const char* source,
const char* dst,
AfCopyFileListener* listener);

All the user has to do is implement an AfCopyFileListener object and pass it to this function...


class MainJob : public AfCopyFileListener{
int OnCopyProgress(long long total,
long long transfered){
 }
}

Pass the Listener object


AfCopyFile af;
af.DoCopy(source, dst, this); 

Disadvantages of the callback mechanism:

Both the callback function in C and Listener in C++ have one common disadvantage:

It makes the code logic hard to read.

We should try to avoid using callback mechanisms and prefer one-way function calls.

Sample code:

AfCopyFile.h


#ifndef _AF_COPY_FILE_H
#define _AF_COPY_FILE_H

class AfCopyFile
{
public:
 //  As an inner class 
 class Listener
 {
 public:
  virtual int OnCopyProgress(long long total, long long transfered) = 0;
 };

public:
 int DoCopy(const char* source, const char* dst, Listener* listener);

};

#endif

AfCopyFile.cpp


#include <stdio.h>
#include <Windows.h>

#include "AfCopyFile.h"


//  will LARGE_INTTEGER Type into unsigned long long
inline unsigned long long translate(LARGE_INTEGER num)
{
 unsigned long long result = num.HighPart;
 result <<= 32;
 result += num.LowPart;
 return result;
}

//  The callback function 
//  Note: this function is required to be keyword CALLBACK This is Windows API Requirements) 
static DWORD CALLBACK CopyProgress( 
       LARGE_INTEGER TotalFileSize,
       LARGE_INTEGER TotalBytesTransferred,
       LARGE_INTEGER StreamSize,
       LARGE_INTEGER StreamBytesTransferred,
       DWORD dwStreamNumber,
       DWORD dwCallbackReason,
       HANDLE hSourceFile,
       HANDLE hDestinationFile,
       LPVOID lpData) // <-  This is the up and down file object 
{
 //  Calculated percentage 
 unsigned long long total = translate(TotalFileSize);
 unsigned long long copied = translate(TotalBytesTransferred);

 //  Print the schedule 
 AfCopyFile::Listener* listener = (AfCopyFile::Listener*) lpData;
 listener->OnCopyProgress(total, copied);

 return PROGRESS_CONTINUE;
}

int AfCopyFile::DoCopy(const char* source, const char* dst, Listener* listener)
{
 BOOL ret = CopyFileEx(source, dst,
  &CopyProgress, //  Function to be called back 
  listener,  //  Context object 
  NULL, 0);
 
 return ret ? 0 : -1;
}

main.cpp


#include <stdio.h>
#include <string.h>
#include "AfCopyFile.h"

class MainJob : public AfCopyFile::Listener
{
public:
 int DoJob()
 {
  strcpy(user, "shaofa");
  strcpy(source, "c:\\test\\2.rmvb" );
  strcpy(dst, "c:\\test\\2_copy.rmvb");

  AfCopyFile af;
  af.DoCopy(source, dst, this); //  will this Transfer the past 
 
  return 0;
 }

 int OnCopyProgress(long long total, long long transfered)
 {
  //  Print the schedule 
  int percent = (int) ( (transfered * 100 / total) );  
  printf("[ The user : %s], %s -> %s :  The progress of  %d %%\n", 
   user, source, dst, percent);

  return 0;
 }

private:
 char source[256];
 char dst[256];
 char user[64];
};

int main()
{
 MainJob job;
 job.DoJob();

 return 0;
}

conclusion


Related articles: