Callback
Callback的本质是设置一个函数指针进去,然后在需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。
比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件:
typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK);
void DownloadFile(const char* pURL, DownloadCallback pCallback)
{
……
pCallback (pURL, true);
}
void __stdcall OnDownloadFinished(const char* pURL, bool bOK)
{
……
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Sink
Sink的本质是你按照对方要求实现一个C++接口,然后把你实现的接口设置给对方,对方需要触发事件时调用该接口, COM中连接点就是居于这种方式。还是以上面的Download为例(你调用对方的下载类实现下载功能):
/*对方要求的接口*/
class IDownloadSink
{
public:
virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0;
};
/*对方的实现*/
class CMyDownloader
{
public:
CMyDownloader(IDownloadSink* pSink) : m_pSink(pSink) { }
void DownloadFile(const char* pURL)
{
……
if(m_pSink != NULL)
m_pSink->OnDownloadFinished(pURL, true);
}
private:
IDownloadSink* m_pSink;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
/*你的实现*/
class CMyFile: public IDownloadSink
{
public:
void Download()
{
CMyDownloader downloader(this);
downloader.DownloadFile("www.baidu.com");
}
virtual void OnDownloadFinished(const char* pURL, bool bOK)
{
……
}
}
- 15
Delegate
Delegate的本质是设置成员函数指针给对方,然后让对方在需要触发事件时调用。C#中用Delegate的方式实现Event,让C++程序员很是羡慕,C++中因为语言本身的关系,要实现Delegate还是很麻烦的。上面的例子我们用Delegate的方式实现如下:
class CDownloadDelegateBase
{
public:
virtual void Fire(const char* pURL, bool bOK) = 0;
};
/*模板类,实现代理函数的调用*/
template<typename O, typename T>
class CDownloadDelegate: public CDownloadDelegateBase
{
typedef void (T::*Fun)(const char*, bool);
public:
CDownloadDelegate(O* pObj = NULL, Fun pFun = NULL)
:m_pFun(pFun), m_pObj(pObj)
{ }
virtual void Fire(const char* pURL, bool bOK)
{
if(m_pFun != NULL && m_pObj != NULL)
{
(m_pObj->*m_pFun)(pURL, bOK);
}
}
private:
Fun m_pFun;
O* m_pObj;
};
/*模板函数,创建代理*/
template<typename O, typename T>
CDownloadDelegate<O,T>* MakeDelegate(O* pObject, void (T::*pFun)(const char* pURL, bool))
{
return new CDownloadDelegate<O, T>(pObject, pFun);
}
/*代理函数管理*/
typedef vector<CDownloadDelegateBase*> CDownloadDelegates;
class CDownloadEvent
{
public:
~CDownloadEvent()
{
CDownloadDelegates::iterator it = m_arDelegates.begin();
while (it != m_arDelegates.end())
{
delete *it;
++it;
}
m_arDelegates.clear();
}
void operator += (CDownloadDelegateBase* p)
{
m_arDelegates.push_back(p);
}
void operator -= (CDownloadDelegateBase* p)
{
CDownloadDelegates::iterator it = remove(m_arDelegates.begin(), m_arDelegates.end(), p);
while (it != m_arDelegates.end())
{
delete *it;
++it;
}
m_arDelegates.erase(it, m_arDelegates.end());
}
void operator()(const char* pURL, bool bOK)
{
CDownloadDelegates::iterator it = m_arDelegates.begin();
while (it != m_arDelegates.end())
{
(*it)->Fire(pURL, bOK);
++it;
}
}
private:
CDownloadDelegates m_arDelegates;
};
class CMyDownloaderEx
{
public:
void DownloadFile(const char* pURL)
{
……
downloadEvent(pURL, true);
}
CDownloadEvent downloadEvent;
};
/*应用*/
class CMyFileEx
{
public:
void download()
{
CMyDownloaderEx downloader;
/*添加代理函数*/
downloader.downloadEvent += MakeDelegate(this, &CMyFileEx::OnDownloadFinished);
downloader.DownloadFile("www.baidu.com");
}
virtual void OnDownloadFinished(const char* pURL, bool bOK)
{
……
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
可以看到Delegate的方式代码量比上面其他2种方式多多了,并且上面是固定参数数量和类型的实现方式,如果要实现可变参数,要更加麻烦的多,具体可参考:
http://www.codeproject.com/Articles/11464/Yet-Another-C-style-Delegate-Class-in-Standard-C
http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
std::function(since C++ 11, vs2010)
template< class R, class... Args >
class function<R(Args...)>
- 1
- 2
- 1
- 2
类模板std :: function是一个通用的多态函数包装器。std :: function的实例可以存储,复制和调用任何可调用的目标:函数、lambda表达式、绑定表达式或其他函数对象。
#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
int main()
{
// store a free function
std::function<void(int)> f1 = print_num;
f1(-9);
// store a lambda
std::function<void()> f2 = []() { print_num(123); };
f2();
// store the result of a call to std::bind
std::function<void()> f3 = std::bind(print_num, 12345);
f3();
// store a call to a member function
std::function<void(const Foo&, int)> f4 = &Foo::print_add;
Foo foo(13579);
f4(foo, 1);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
std::mem_fn (since C++ 11, vs2010)
template< class R, class T >
/*unspecified*/ mem_fn(R T::* pm);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...));
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) &);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const &);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) &&);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const &&);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &&);
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &&);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
函数模板std :: mem_fn生成指向成员函数的指针的包装对象,它可以存储,复制和调用指向成员函数的指针。 在调用std :: mem_fn时,可以使用对象的引用和指针(包括智能指针)。
/* Use mem_fn to store and execute a member function:*/
#include <functional>
#include <iostream>
struct Foo {
void display_greeting() {
std::cout << "Hello, world.\n";
}
void display_number(int i) {
std::cout << "number: " << i << '\n';
}
};
int main()
{
Foo foo;
auto func_greet = std::mem_fn(&Foo::display_greeting);
func_greet(foo);
auto func_display = std::mem_fn(&Foo::display_number);
func_display(foo, 42);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
#include <iostream>
#include <functional>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
/*Pass a member function to std::transform to create a sequence of numbers:*/
std::vector<std::string> words = {"It", "is", "a", "test"};
std::vector<std::unique_ptr<std::string>> words2;
words2.emplace_back(new std::string("another"));
words2.emplace_back(new std::string("test"));
std::vector<std::size_t> lengths;
std::transform(words.begin(),
words.end(),
std::back_inserter(lengths),
std::mem_fn(&std::string::size));
// uses references to strings
std::transform(words2.begin(), words2.end(),
std::back_inserter(lengths),
std::mem_fn(&std::string::size));
// uses unique_ptr to strings
std::cout << "The string lengths are ";
for(auto n : lengths)
std::cout << n << ' ';
std::cout << '\n';
}
template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1,
OutputIt d_first, UnaryOperation unary_op)
{
while (first1 != last1) {
*d_first++ = unary_op(*first1++);
}
return d_first;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
小结
1) Callback方法是面向过程的,使用简单而且灵活,正如C语言本身;
2) Sink方法是面向对象的,在C++里使用较多, 可以在一个Sink里封装一组回调接口,适用于一系列比较固定的回调事件;
3) Delegate方法也是面向对象的,和Sink封装一组接口不同,Delegate的封装是以函数为单位,粒度比Sink更小更灵活;
4) std::function和std::bind组合使用也可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时(本质上讲全局函数和静态成员函数没有区别,使用方法上除了静态成员函数在引用时要在前面加域作用符classname::外,没有其它任何区别;事实上全局函数也有可能放入命名空间或者使用全局域作用符,例如 namespace::function() 或::function,这样不仅本质上相同,形势上也与静态成员函数一致了)。在Effective C++中ITEM35建议使用该方法实现Strategy模式,实际上也可以用于代替callback 函数模仿C#中的event对象,而这里只能实现一个函数,实际上如果function<>模板实现了operator+以后,再在 function对象中维护一个列表,便可以实现C#中的event特性,即Delegate。