作者neigence ()
站內C_and_CPP
標題Re: [問題] parameter 是 template function pointer
時間Sat Aug 7 01:36:08 2010
我剛才解決我的問題了 關於 template和 function pointer的結合
有興趣和耐心的人 可以看一下以下的程式 (ps.很長哦 非常長)
相信有寫過網路程式的人都遇過這問題,我暫用cin 來代表網路收進來的字串
class Device{
void doA(){ .... }
void doB(){ .... }
}
void main(){
Device device;
string messageFromNetwork;
while(true){
cin >> messageFromNetwork; //假設我輸入
if(messageFromNetwork == "a ")
device.doA();
else if(messageFromNetwork == "b")
device.doB();
}
}
我們通常要去用if 來判斷字串的"內容" 來決定呼叫那個函式,那有沒有辨法
不用任何if就可以做到 讓他呼叫想要的函式呢????
以下 我就是要偷懶~我就是不想用if.........
假設 我有2種device
class Device;
class AngelDevice : public Device
class DemonDevice : public Device
-----------------------Device.h----------------------------------
class Device{
public:
Device();
virtual void doAddItem(string parameter);
virtual void doDelItem(string parameter);
virtual void doShowItem(string parameter);
virtual void execute(string command,string parameter)=0;
protected:
int item_number;
};
-----------------------------------------------------------------
----------------------Device.cpp---------------------------------
Device::Device(){
item_number = 0;
}
void Device::doAddItem(string parameter){
int num = atoi(parameter.c_str());
item_number += num;
}
void Device::doDelItem(string parameter){
int num = atoi(parameter.c_str());
item_number -= num;
}
void Device::doShowItem(string parameter){
std::cout << item_number << endl;
}
-----------------------------------------------------------------
一個device有一個屬性叫 item_number代表你有的道具數量
device是一個abstract class 不能被new
doAddItem 則加一個道具
doDelItem 則減一個道具
doShowItem則印出有多少道具
execute等下說明
而有2種device繼承自device 就是AngelDevice , DemonDevice
-----------------------AngelDevice.h-----------------------------
class AngelDevice : public Device{
typedef void (AngelDevice::*APTR)(string);
public:
AngelDevice();
virtual ~AngelDevice();
virtual void doAddItem(string parameter);
virtual void doDelItem(string parameter);
virtual void doTwiceItem(string parameter);
virtual void execute(string command,string parameter);
protected:
Commander<AngelDevice> commander;
};
-----------------------------------------------------------------
----------------------AngelDevice.cpp-----------------------------
AngelDevice::AngelDevice(){
commander.addInvocation("add",&AngelDevice::doAddItem);
commander.addInvocation("del",&AngelDevice::doDelItem);
commander.addInvocation("twice",&AngelDevice::doTwiceItem);
commander.addInvocation("show",&AngelDevice::doShowItem);
}
AngelDevice::~AngelDevice(){
}
void AngelDevice::doAddItem(string parameter){
int num = atoi(parameter.c_str());
item_number += num*2;
}
void AngelDevice::doDelItem(string parameter){
int num = atoi(parameter.c_str());
item_number -= num/2;
}
void AngelDevice::doTwiceItem(string parameter){
item_number*=2;
}
void AngelDevice::execute(string command,string parameter){
APTR ptr = commander.getInvocation(command);
if(ptr)
(this->*ptr)(parameter);
}
---------------------------------------------------------------
AngelDevice 是一種 天使的裝置,如果add item則會得到2倍
del item則只扣除一半,另外還有一個新函式叫
twiceitem 可以讓道具加倍
-------------------------DemonDevice.h------------------------
class DemonDevice : public Device{
typedef void (DemonDevice::*DPTR)(string);
public:
DemonDevice();
virtual ~DemonDevice();
virtual void doAddItem(string parameter);
virtual void doDelItem(string parameter);
virtual void doHalfItem(string parameter);
virtual void execute(string command,string parameter);
protected:
Commander<DemonDevice> commander;
};
---------------------------------------------------------------
--------------------------DemonDevice.cpp----------------------
DemonDevice::DemonDevice(){
commander.addInvocation("add",&DemonDevice::doAddItem);
commander.addInvocation("del",&DemonDevice::doDelItem);
commander.addInvocation("half",&DemonDevice::doHalfItem);
commander.addInvocation("show",&DemonDevice::doShowItem);
}
DemonDevice::~DemonDevice(){
}
void DemonDevice::doAddItem(string parameter){
int num = atoi(parameter.c_str());
item_number += num/2;
}
void DemonDevice::doDelItem(string parameter){
int num = atoi(parameter.c_str());
item_number -= num*2;
}
void DemonDevice::doHalfItem(string parameter){
item_number/=2;
}
void DemonDevice::execute(string command,string parameter){
DPTR ptr = commander.getInvocation(command);
if(ptr)
(this->*ptr)(parameter);
}
-------------------------------------------------------------
demon device是另外一種裝置,add item只能拿到一半
del item則被扣除2倍,另外還有一個half item讓道具減半
按照傳統的做法 你的main應該是長這樣
void main(){
AngelDevice device;
string msgFromNet;
while(true){
cin >> msgFromNet;
string command = msgFromNet.substr(0,msgFromNet.find(" "));
string parameter = msgFromNet.substr(msgFromNet.find(" ")+1);
// if msgFromNet = add 123 then command = add,param = 123
if(command =="add")
device.doAddItem(parameter);
else if(command == "del")
device.doDelItem(parameter);
else if(command == "show")
device.doShowItem(parameter);
else if(command == "twice")
device.doTwiceItem(parameter);
}
}
為了不想看到這個if 所以 我新增了 Commander利用template + function pointer
來解決
----------------------Commander.h------------------------------------
template <typename T>
class Commander{
public:
void addInvocation(string command,void (T::*fptr)(string)){
cmdMap[command] = fptr;
}
void (T::*getInvocation(string command))(string){
return cmdMap[command];
}
protected:
map<string,void (T::*)(string)> cmdMap;
};
----------------------------------------------------------------------
這個是呼應該AngelDevice , DemonDevice 剛才建構子中的
AngelDevice :
commander.addInvocation("add",&AngelDevice::doAddItem);
commander.addInvocation("del",&AngelDevice::doDelItem);
commander.addInvocation("twice",&AngelDevice::doTwiceItem);
commander.addInvocation("show",&AngelDevice::doShowItem);
DemonDevice :
commander.addInvocation("add",&DemonDevice::doAddItem);
commander.addInvocation("del",&DemonDevice::doDelItem);
commander.addInvocation("half",&DemonDevice::doHalfItem);
commander.addInvocation("show",&DemonDevice::doShowItem);
將命令字串和函式做 connect
以後 main 就如以下所示
void main(){
string command,parameter;
AngelDevice device;
while(true){
std::cin >> command >> parameter;
device.execute(command,parameter);
}
}
重點是在 將 string 和 function pointer做結合,並放在map之中
接著 透過 template來完成
需要include : <iostream> <string> <map>
後記 : 在高手如雲的c++版 這也許有點野人獻曝啦
c++真的是方便 透過這樣子做 只需少許class 就可以完成
不像以前用if else 或者 把每個命令都編成class 使用Command Pattern
or Decorate Pattern
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 219.70.172.147
→ loveme00835:mem_fun 08/07 02:23
→ neigence:什麼!! 竟然有這種東西可以用!!! 我覺得好丟臉= = 08/07 02:41
推 avhacker:太長懶得看,不過我猜boost.bind, boost.function 更合用 08/07 03:02
→ tinlans:effective c++ 就推薦過 boost 的 bind 跟 function 了啊 08/07 03:03
→ tinlans:其實環境有支援 TR1 的話也能直接用 TR1 的函式庫。 08/07 03:04
→ tinlans:不過手寫一遍也沒差,就當作是練習 T::* 和 ->*。 08/07 03:06
→ tinlans:只是你都用了 C++ 還在寫 atoi(),就不得不唸一下了。 08/07 03:06
→ loveme00835:雖然我也推 bind, 還是請原po都比較看看 08/07 03:06
→ neigence:真的很感謝樓上大大們的推文..!! 受益良多 08/07 03:07
→ tinlans:建議把 atoi() 改成 istringstream。 08/07 03:08
→ tinlans:atoi() 傳回 0 的時候很難判斷是轉錯還是真的是 0。 08/07 03:08
→ loveme00835:lexical_cast 也不錯 XD 08/07 03:10
→ tinlans:是不錯,只是它會丟 exception 讓我有點不愛用。 08/07 04:24