title: C++實現(xiàn)委托機制
cplus11_feature_E
purpose
prproject is to introduce C++ 11 new feature which could promote development efficience and rubust
C++ 委托機制
在GUI編程或者基于事件開發(fā)的項目中,經(jīng)常需要使用回調(diào)函數(shù). 為了處理這類回調(diào)事件, C# 特別提供了關鍵字delegate來實現(xiàn).
函數(shù)指針回調(diào)做法
在傳統(tǒng)的C++開發(fā)過程中, 為了實現(xiàn)函數(shù)回調(diào),一般的做法是將 C++ 的函數(shù)指針傳給管理者.當有事件觸發(fā)時,再執(zhí)行該回調(diào)函數(shù).
基于函數(shù)指針的回調(diào)方式有一下缺點:
- 對萌新不友好, 上手困難
- 函數(shù)指針操作并不安全,無法在編譯階段檢測來
C++11 新特性
為了解決此類問題, C++11 從boost庫中借鑒了新特性 functional, 以此為容器存儲函數(shù)指針,從而優(yōu)雅的實現(xiàn)回調(diào)機制
案例演示:
- 存儲自由函數(shù)
- 存儲lambda表達式
- 存儲std::bind 結(jié)果 (非常重要)
- 存儲類成員方法和類實例
- 存儲類成員方法和類實例指針
- 存儲結(jié)構(gòu)體方法
#pragma once
#include <functional>
#include <iostream>
void print_num(int i);
inline void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum {
void operator()(int i) const
{
std::cout << i << '\n';
}
};
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_ + i << '\n'; }
int num_;
};
void main();
inline void main()
{
// store a free function
std::function<void(int)> f_display = print_num;
f_display(-9);
// store a lambda
std::function<void()> f_display_42 = []() { print_num(42); };
f_display_42();
//store the result of a call to std::bind
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();
// //store a call to a member function
//std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
const Foo foo(314159);
//f_add_display(foo, 1);
//store a call to a data member accessor
//std::function<int(Foo const&)> f_num = &Foo::num_;
//std::cout << "num_: " << f_num(foo) << '\n';
// store a call to a member function and object
using std::placeholders::_1;
std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
f_add_display2(2);
// store a call to a member function and object ptr
std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
f_add_display3(3);
// store a call to a function object
std::function<void(int)> f_display_obj = PrintNum();
f_display_obj(18);
}
委托機制實現(xiàn)演示
class IObj
{
public:
virtual int callback(string t_data) = 0;
};
class AppleObj : public IObj
{
public:
virtual int callback(string t_data) final
{
cout << "this is appleobj : "<<endl;
return 0;
}
};
class BananaObj : public IObj
{
public:
virtual int callback( string t_data) final
{
cout << "this is banana object: " << endl;
return 1;
}
};
class DeleManager
{
public:
DeleManager() {};
~DeleManager() {};
void addObj(function<int(string)> t_dele)
{
_dele_list.push_back(t_dele);
}
void notify(string t_msg)
{
if (_dele_list.empty())
{
cout << "list is empty " << endl;
return;
}
for (auto itor : _dele_list)
{
itor(t_msg);
}
}
private:
vector <function<int(string)>> _dele_list;
#pragma region MAIN
public:
static void main()
{
DeleManager i_manager;
AppleObj i_apple;
BananaObj i_banana;
using std::placeholders::_1;
std::function<int(string)> i_dele_apple = std::bind(&AppleObj::callback, i_apple, _1);
i_manager.addObj(i_dele_apple);
std::function<int(string)> i_dele_banana = std::bind(&BananaObj::callback, i_banana, _1);
i_manager.addObj(i_dele_banana);
i_manager.notify("happy middle september day");
}
#pragma endregion MAIN
};
windows消息回調(diào)
在windows GUI 開發(fā)過程中, 一般通過 postmessage 來完成消息回調(diào),觸發(fā)GUI執(zhí)行對應的操作. 這種方式簡單易行,對萌新友好,且具備跨線程操作的功能. 但是postmessage 也有自身的缺陷:
- 過渡依賴windows消息機制
- 回調(diào)傳參可定制程度低
總結(jié)
為了解決GUI 跨線程操作界面的導致主線程崩潰的情況, C++ 11 終于推出了自己的thread 類
thread 類提供detach() 的方法, 讓worker線程也具備了操作GUI的能力.
在GUI開發(fā)中, 通過使用function 和 thread等C++ 11 新特性,能夠更便捷的開發(fā)出高質(zhì)量的程序, 同時回避開發(fā)過程中的問題