#
超級(jí)怪物在北京時(shí)間2009年6月26日——也就是今天逝世了,曾經(jīng)是多么的喜愛這位歌星,被他的舞步感動(dòng)得不可自控,模仿著他的步伐,欣賞著他的歌喉,感受著他帶給音樂世界的瘋狂。
不禁要感嘆,人死的真是太快了......
boost::bind(&memberfunction, obj, _1, _2........)類似這樣的用法,我們叫做成員函數(shù)綁定,boost庫(kù)的文檔中說(shuō)的很清楚,第一個(gè)參數(shù)可以是value、pointer和reference,即傳值、傳地址和傳引用都是可以的,所以在一般情況下,下面三種使用bind的形式都是成立的。

class A


{
public:
void func();
};


A a;
A& r = a;

boost::bind(&A::func, a);
boost::bind(&a::func, &a);
boost::bind(&a::func, r);
由上面的代碼可以看出,我們可以隨便傳任意一種類對(duì)象的形式,函數(shù)模板會(huì)自動(dòng)尋找最為匹配的為我們實(shí)現(xiàn)。但是有兩種情況是特殊的,即:
1、該對(duì)象不可進(jìn)行拷貝構(gòu)造函數(shù)。
2、該對(duì)象不可隨意被析構(gòu)。
發(fā)現(xiàn)這個(gè)問(wèn)題是在我編寫單件模式時(shí)的遇見的,當(dāng)時(shí)發(fā)現(xiàn)我的單件對(duì)象在bind中被析構(gòu)了一次,這很不尋常,為什么bind會(huì)調(diào)用第一個(gè)參數(shù)的析構(gòu)呢?跟蹤進(jìn)了boost的源碼才發(fā)現(xiàn),原來(lái)所有的參數(shù)都會(huì)被拷貝一遍,然后析構(gòu)一遍,這樣一來(lái),我們傳遞參數(shù)的時(shí)候就會(huì)有一些小麻煩了,首先必須保證參數(shù)能夠被拷貝而不影響邏輯和數(shù)據(jù)一致性,其次,參數(shù)能夠被析構(gòu)而不影響邏輯和數(shù)據(jù)一致性。單件是全局性質(zhì)的數(shù)據(jù),所以絕對(duì)不可以析構(gòu),那么這種情況的話,我們只好傳遞單件對(duì)象的地址,而不能傳遞值或引用。
另:附上出錯(cuò)問(wèn)題的代碼如下
class InputDevice
: public EventSource
, public Singleton<InputDevice>


{
public:
};

class TestUI
: public Singleton<TestUI>


{
public:

~TestUI()
{
std::cout<<"~TestUI"<<std::endl;
}

void processKeyboard(EventArgs& args)
{
std::cout<<"鍵盤響應(yīng)"<<std::endl;
}


void processMouse(EventArgs& args)
{
std::cout<<"鼠標(biāo)響應(yīng)"<<std::endl;
}
};


int _tmain(int argc, _TCHAR* argv[])


{
new FrameUpdaterManager;
new DelayEventSender;
new InputDevice;
new TestUI;

InputDevice::getSingleton().mEventSet.addEvent("KeyDown", Event());
InputDevice::getSingleton().mEventSet.addEvent("KeyUp", Event());
InputDevice::getSingleton().mEventSet.addEvent("MouseLDown", Event());
InputDevice::getSingleton().mEventSet.addEvent("MouseLUp", Event());
InputDevice::getSingleton().mEventSet.addEvent("MouseRDown", Event());
InputDevice::getSingleton().mEventSet.addEvent("MouseRUp", Event());


//TestUI& ui = TestUI::getSingleton(); // 用此行便會(huì)出錯(cuò)
TestUI* ui = TestUI::getSingletonPtr();

// 出錯(cuò)開始
InputDevice::getSingleton().mEventSet["KeyDown"] += boost::bind(&TestUI::processKeyboard, ui, _1);
InputDevice::getSingleton().mEventSet["KeyUp"] += boost::bind(&TestUI::processKeyboard, ui, _1);

InputDevice::getSingleton().mEventSet["MouseLDown"] += boost::bind(&TestUI::processMouse, ui, _1);
InputDevice::getSingleton().mEventSet["MouseLUp"] += boost::bind(&TestUI::processMouse, ui, _1);
InputDevice::getSingleton().mEventSet["MouseRDown"] += boost::bind(&TestUI::processMouse, ui, _1);
InputDevice::getSingleton().mEventSet["MouseRUp"] += boost::bind(&TestUI::processMouse, ui, _1);


delete TestUI::getSingletonPtr();
delete InputDevice::getSingletonPtr();
delete DelayEventSender::getSingletonPtr();
delete FrameUpdaterManager::getSingletonPtr();
return 0;
}

log4cxx是一個(gè)不錯(cuò)的庫(kù),利用配置文件就可以很靈活的使用它。
說(shuō)說(shuō)具體用法,首先當(dāng)然是在你的C++代碼中寫上Log的各種東西了
#include <log4cxx/logger.h>
#include <log4cxx/logstring.h>
#include <log4cxx/propertyconfigurator.h>

int _tmain(int argc, _TCHAR* argv[])


{
using namespace log4cxx;

// 讀取配置文件
PropertyConfigurator::configure("log4cxx.cfg");

// 建立兩個(gè)logger
LoggerPtr logger1 = Logger::getLogger("TraceYourMama");
LoggerPtr logger2 = Logger::getLogger("Patch");

LOG4CXX_TRACE(logger1, "跟蹤");
LOG4CXX_WARN(logger1, "警告");
LOG4CXX_DEBUG(logger1, "調(diào)試");
LOG4CXX_ASSERT(logger1, false, "斷言");
LOG4CXX_FATAL(logger1, "致命");

LOG4CXX_TRACE(logger2, "跟蹤");
LOG4CXX_ERROR(logger2, "錯(cuò)誤");
return 0;
}

其實(shí)在實(shí)際應(yīng)用中,每個(gè)類都可以搞一個(gè)logger,然后在配置文件中進(jìn)行如下的設(shè)置:
# 設(shè)置root logger為DEBUG級(jí)別
#log4j.rootLogger=TRACE,ca
log4j.logger.TraceYourMama=ERROR,fa,ha
log4j.logger.Patch=Trace,ca

#設(shè)置spirit為TRACE級(jí)別
#log4j.spirit=DEBUG
#log4j.additivity.spirit=false


# %m - message
# %n - 回車
# %d - 時(shí)間
# %.16c - Logger名稱
# %-5p - log級(jí)別
# %t - thread_id



#對(duì)Appender ca進(jìn)行設(shè)置:
#這是一個(gè)控制臺(tái)類型的Appender
#輸出格式(layout)為PatternLayout
log4j.appender.ca=org.apache.log4j.ConsoleAppender
log4j.appender.ca.layout=org.apache.log4j.PatternLayout
log4j.appender.ca.layout.ConversionPattern=%d %-5p %.16c - %m%n





#對(duì)Appender fa進(jìn)行設(shè)置:
# 這是一個(gè)文件類型的Appender,
# 其輸出文件(File)為./debug.log,
# 輸出方式(Append)為覆蓋方式,
# 輸出格式(layout)為PatternLayout
log4j.appender.fa=org.apache.log4j.FileAppender
log4j.appender.fa.File=./debug.log
log4j.appender.fa.Append=true
log4j.appender.fa.layout=org.apache.log4j.PatternLayout
#log4j.appender.fa.layout.ConversionPattern=%d [%t] %-5p %.16c %x - %m%n
log4j.appender.fa.layout.ConversionPattern=%d %-5p %.16c - %m%n



接觸了boost的狀態(tài)機(jī),發(fā)現(xiàn)不是想象中的那么好用,在一些地方還得用上mpl庫(kù)里的東西,由于對(duì)模板元編程不是很熟練,搞了好些天才算弄明白這該死的mpl::list的原理和用法。
boost的狀態(tài)機(jī)是屬于靜態(tài)鏈接的狀態(tài)機(jī),也就是說(shuō),它的圖結(jié)構(gòu)是編譯期間就確定了的,在運(yùn)行時(shí)不可以動(dòng)態(tài)配置。所以,它的用途是有一定局限性的,但在一般情況下,它不僅很通用,而且在你會(huì)用并熟練地情況下,還會(huì)很好用,用起來(lái)很舒服,邏輯也很合理。下面就是一段代碼,當(dāng)然也是借鑒了別人的東西,自己修改了一下,在MainState中添加了一個(gè)Transition做了測(cè)試,因?yàn)榇饲拔疫€不知道一個(gè)狀態(tài)如何包含多個(gè)Transition,呵呵,原來(lái)是用mpl::list來(lái)做。至于這個(gè)狀態(tài)機(jī)的入門教程,網(wǎng)上隨處可見的三部曲:《boost 狀態(tài)機(jī)入門教程》說(shuō)得很清楚。
1 #include <iostream>
2 #include <ctime>
3
4 #include <boost/statechart/transition.hpp>
5 #include <boost/statechart/event.hpp>
6 #include <boost/statechart/state_machine.hpp>
7 #include <boost/statechart/simple_state.hpp>
8
9 namespace sc = boost::statechart;
10
11
12
13 class EvtStartStop : public sc::event<EvtStartStop>{};
14 class EvtReset : public sc::event<EvtReset>{};
15 class EvtGo : public sc::event<EvtGo>{};
16
17
18 class MainState;
19 class StopState;
20 class RunState;
21 class TwoState;
22
23 class Machine : public sc::state_machine<Machine, MainState>
24 {};
25
26
27
28
29
30
31 class MainState : public sc::simple_state<MainState, Machine, StopState>
32 {
33 public:
34 typedef sc::transition<EvtReset, MainState> reactReset;
35 typedef sc::transition<EvtGo, TwoState> reactGo;
36 typedef boost::mpl::list<reactReset, reactGo> reactions;
37
38 MainState(void){
39 std::cout<<"進(jìn)入MainState"<<std::endl;
40 mTime = 0;
41 }
42
43 ~MainState(void){
44 std::cout<<"退出MainState"<<std::endl;
45 }
46
47 double mTime;
48 };
49
50
51 // 該狀態(tài)屬于無(wú)用狀態(tài),用于測(cè)試mpl::list的多transition用法
52 class TwoState : public sc::simple_state<TwoState, Machine>
53 {
54 public:
55 typedef sc::transition<EvtGo, MainState> reactions;
56
57 TwoState(void){
58 std::cout<<"進(jìn)入TwoState"<<std::endl;
59 }
60
61 ~TwoState(void){
62 std::cout<<"退出TwoState"<<std::endl;
63 }
64 };
65
66
67 class StopState : public sc::simple_state<StopState, MainState>
68 {
69 public:
70 typedef sc::transition<EvtStartStop, RunState> reactions;
71 StopState(void){
72 std::cout<<"進(jìn)入StopState"<<std::endl;
73 }
74
75 ~StopState(void){
76 std::cout<<"退出StopState"<<std::endl;
77 }
78 };
79
80 class RunState : public sc::simple_state<RunState, MainState>
81 {
82 public:
83 typedef sc::transition<EvtStartStop, StopState> reactions;
84 RunState(void){
85 std::cout<<"進(jìn)入RunState"<<std::endl;
86 mStartTime = 0;
87 }
88
89 ~RunState(void){
90 std::cout<<"退出RunState"<<std::endl;
91 context<MainState>().mTime += std::difftime(std::time(0), mStartTime);
92 }
93
94 std::time_t mStartTime;
95 };
96
97
98 int _tmain(int argc, _TCHAR* argv[])
99 {
100 Machine mc;
101 mc.initiate();
102
103 mc.process_event(EvtStartStop());
104 mc.process_event(EvtStartStop());
105 mc.process_event(EvtReset());
106 mc.process_event(EvtGo());
107 mc.process_event(EvtGo());
108
109 return 0;
110 }
寫模版多了的人,必然會(huì)遇到這樣那樣的問(wèn)題,模版特例化就是解決了一個(gè)經(jīng)常碰見的問(wèn)題:如果我們需要根據(jù)某些特殊的模版參數(shù)類型來(lái)重新實(shí)現(xiàn)一下算法的話,該怎么辦呢?說(shuō)的多了那也沒什么用,我們就寫一個(gè)會(huì)做除法的類吧。這個(gè)類在做整數(shù)除法的時(shí)候會(huì)同時(shí)求出余數(shù),而在算其他類型時(shí)是不求的。代碼如下:
1
#include <iostream>
2
3
4
template<typename Ty>
5
class Division
6

{
7
public:
8
Division(Ty dividend, Ty divisor)
9
:mDividend(dividend), mDivisor(divisor)
{}
10
public:
11
void show()
12
{
13
std::cout<<"結(jié)果 = "<<mDividend/mDivisor<<std::endl;
14
}
15
16
Ty mDividend, mDivisor;
17
};
18
19
template<>
20
inline void Division<int>::show()
21

{
22
std::cout<<"結(jié)果 = "<<mDividend/mDivisor<<std::endl;
23
std::cout<<"余數(shù) = "<<mDividend%mDivisor<<std::endl;
24
}
25
26
27
28
29
int _tmain(int argc, _TCHAR* argv[])
30

{
31
Division<int> a(20, 11);
32
a.show();
33
34
Division<float> b(20.0f, 11.0f);
35
b.show();
36
return 0;
37
}
以上這種方式就叫做局部特化,關(guān)于全部特化和局部特化、全特化和偏特化,我認(rèn)為他們之間的關(guān)系很緊密,界限也很模糊,硬要分類的話,以上面的Division類為例,就看下面的代碼對(duì)全部特化和局部特化的區(qū)別吧:
1 /**
2 @remark
3 Division的全部特化
4 */
5 template<>
6 class Division<int>
7 {
8 public:
9 Division(Ty dividend, Ty divisor)
10 :mDividend(dividend), mDivisor(divisor){}
11 public:
12 void show()
13 {
14 std::cout<<"結(jié)果 = "<<mDividend/mDivisor<<std::endl;
15 std::cout<<"余數(shù) = "<<mDividend%mDivisor<<std::endl;
16 }
17
18 Ty mDividend, mDivisor;
19 };
20
21 /**
22 @remark
23 Division的局部特化
24 */
25 template<>
26 inline void Division<int>::show()
27 {
28 std::cout<<"結(jié)果 = "<<mDividend/mDivisor<<std::endl;
29 std::cout<<"余數(shù) = "<<mDividend%mDivisor<<std::endl;
30 }
上面的代碼只是說(shuō)明了全部特化和局部特化,并沒有說(shuō)明什么事全特化和偏特化。其實(shí),對(duì)于只有一個(gè)參數(shù)的模版類型來(lái)說(shuō),并沒有什么全特化和偏特化的區(qū)別,但如果是一個(gè)以上的模板參數(shù),那就是由區(qū)別的了,如下:
1 /**
2 @remark
3 原始模板類
4 */
5 template<typename Ty, typename TyEx>
6 class ObjectData
7 {
8 //
9 };
10
11 /**
12 @remark
13 Object的全特化
14 */
15 template<>
16 class ObjectData<int, float>
17 {
18 //
19 };
20
21 /**
22 @remark
23 Object的偏特化,只特化第一個(gè)參數(shù)
24 */
25 template<typename TyEx>
26 class ObjectData<int, TyEx>
27 {
28 //
29 };
以上僅為個(gè)人觀點(diǎn),錯(cuò)誤之處請(qǐng)指正。