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