Re: [問題] parameter 是 template function pointer

看板C_and_CPP作者時間15年前 (2010/08/06 17:36), 編輯推噓1(1012)
留言13則, 4人參與, 最新討論串2/3 (看更多)
我剛才解決我的問題了 關於 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

08/07 02:23, , 1F
mem_fun
08/07 02:23, 1F

08/07 02:41, , 2F
什麼!! 竟然有這種東西可以用!!! 我覺得好丟臉= =
08/07 02:41, 2F

08/07 03:02, , 3F
太長懶得看,不過我猜boost.bind, boost.function 更合用
08/07 03:02, 3F

08/07 03:03, , 4F
effective c++ 就推薦過 boost 的 bind 跟 function 了啊
08/07 03:03, 4F

08/07 03:04, , 5F
其實環境有支援 TR1 的話也能直接用 TR1 的函式庫。
08/07 03:04, 5F

08/07 03:06, , 6F
不過手寫一遍也沒差,就當作是練習 T::* 和 ->*。
08/07 03:06, 6F

08/07 03:06, , 7F
只是你都用了 C++ 還在寫 atoi(),就不得不唸一下了。
08/07 03:06, 7F

08/07 03:06, , 8F
雖然我也推 bind, 還是請原po都比較看看
08/07 03:06, 8F

08/07 03:07, , 9F
真的很感謝樓上大大們的推文..!! 受益良多
08/07 03:07, 9F

08/07 03:08, , 10F
建議把 atoi() 改成 istringstream。
08/07 03:08, 10F

08/07 03:08, , 11F
atoi() 傳回 0 的時候很難判斷是轉錯還是真的是 0。
08/07 03:08, 11F

08/07 03:10, , 12F
lexical_cast 也不錯 XD
08/07 03:10, 12F

08/07 04:24, , 13F
是不錯,只是它會丟 exception 讓我有點不愛用。
08/07 04:24, 13F
文章代碼(AID): #1CN4WBAs (C_and_CPP)
文章代碼(AID): #1CN4WBAs (C_and_CPP)