﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-c++初学者-随笔分类-C++</title><link>http://www.cppblog.com/tgh621/category/8152.html</link><description>专注技术开发</description><language>zh-cn</language><lastBuildDate>Wed, 14 Jan 2009 06:14:40 GMT</lastBuildDate><pubDate>Wed, 14 Jan 2009 06:14:40 GMT</pubDate><ttl>60</ttl><item><title>用WaitForSingleObject等待事件处理</title><link>http://www.cppblog.com/tgh621/archive/2009/01/12/71782.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Mon, 12 Jan 2009 02:17:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2009/01/12/71782.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/71782.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2009/01/12/71782.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/71782.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/71782.html</trackback:ping><description><![CDATA[<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ClearMessage(HWND&nbsp;hWnd,BOOL&nbsp;bExtMsg)<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img id=Codehighlighter1_42_535_Open_Image onclick="this.style.display='none'; Codehighlighter1_42_535_Open_Text.style.display='none'; Codehighlighter1_42_535_Closed_Image.style.display='inline'; Codehighlighter1_42_535_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_42_535_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_42_535_Closed_Text.style.display='none'; Codehighlighter1_42_535_Open_Image.style.display='inline'; Codehighlighter1_42_535_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_42_535_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_42_535_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MSG&nbsp;GetMsg;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(PeekMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg,hWnd,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,PM_REMOVE))<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img id=Codehighlighter1_106_211_Open_Image onclick="this.style.display='none'; Codehighlighter1_106_211_Open_Text.style.display='none'; Codehighlighter1_106_211_Closed_Image.style.display='inline'; Codehighlighter1_106_211_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_106_211_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_106_211_Closed_Text.style.display='none'; Codehighlighter1_106_211_Open_Image.style.display='inline'; Codehighlighter1_106_211_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_106_211_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_106_211_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(GetMsg.message&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;WM_TIMER)&nbsp;</span><span style="COLOR: #0000ff">continue</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hWnd&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;bExtMsg)<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img id=Codehighlighter1_246_533_Open_Image onclick="this.style.display='none'; Codehighlighter1_246_533_Open_Text.style.display='none'; Codehighlighter1_246_533_Closed_Image.style.display='inline'; Codehighlighter1_246_533_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_246_533_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_246_533_Closed_Text.style.display='none'; Codehighlighter1_246_533_Open_Image.style.display='inline'; Codehighlighter1_246_533_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_246_533_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_246_533_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(PeekMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg,NULL,WM_WINDOWPOSCHANGING,WM_WINDOWPOSCHANGED,PM_REMOVE))<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img id=Codehighlighter1_337_402_Open_Image onclick="this.style.display='none'; Codehighlighter1_337_402_Open_Text.style.display='none'; Codehighlighter1_337_402_Closed_Image.style.display='inline'; Codehighlighter1_337_402_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_337_402_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_337_402_Closed_Text.style.display='none'; Codehighlighter1_337_402_Open_Image.style.display='inline'; Codehighlighter1_337_402_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_337_402_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_337_402_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(PeekMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg,NULL,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,PM_QS_PAINT))<br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img id=Codehighlighter1_465_530_Open_Image onclick="this.style.display='none'; Codehighlighter1_465_530_Open_Text.style.display='none'; Codehighlighter1_465_530_Closed_Image.style.display='inline'; Codehighlighter1_465_530_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_465_530_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_465_530_Closed_Text.style.display='none'; Codehighlighter1_465_530_Open_Image.style.display='inline'; Codehighlighter1_465_530_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_465_530_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_465_530_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">GetMsg);<br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CExportRegeditToXml::OnBnClickedCancel()<br></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img id=Codehighlighter1_584_943_Open_Image onclick="this.style.display='none'; Codehighlighter1_584_943_Open_Text.style.display='none'; Codehighlighter1_584_943_Closed_Image.style.display='inline'; Codehighlighter1_584_943_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_584_943_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_584_943_Closed_Text.style.display='none'; Codehighlighter1_584_943_Open_Image.style.display='inline'; Codehighlighter1_584_943_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_584_943_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_584_943_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">27</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">28</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(&nbsp;NULL&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;m_TransRegedit&nbsp;)&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;(&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">pThreadData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_brepalce)&nbsp;)&nbsp;<br></span><span style="COLOR: #008080">30</span><span style="COLOR: #000000"><img id=Codehighlighter1_657_927_Open_Image onclick="this.style.display='none'; Codehighlighter1_657_927_Open_Text.style.display='none'; Codehighlighter1_657_927_Closed_Image.style.display='inline'; Codehighlighter1_657_927_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_657_927_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_657_927_Closed_Text.style.display='none'; Codehighlighter1_657_927_Open_Image.style.display='inline'; Codehighlighter1_657_927_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_657_927_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_657_927_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(MessageBox(_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">目前正在导出注册表，是否取消!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">),_T(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">警告</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">),MB_YESNO)</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">IDYES)<br></span><span style="COLOR: #008080">32</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">33</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pThreadData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_brepalce&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;TRUE;<br></span><span style="COLOR: #008080">34</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">35</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(m_TransRegedit&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;WaitForSingleObject(m_TransRegedit</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hThread,</span><span style="COLOR: #000000">40</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">WAIT_OBJECT_0)&nbsp;<br></span><span style="COLOR: #008080">36</span><span style="COLOR: #000000"><img id=Codehighlighter1_866_899_Open_Image onclick="this.style.display='none'; Codehighlighter1_866_899_Open_Text.style.display='none'; Codehighlighter1_866_899_Closed_Image.style.display='inline'; Codehighlighter1_866_899_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_866_899_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_866_899_Closed_Text.style.display='none'; Codehighlighter1_866_899_Open_Image.style.display='inline'; Codehighlighter1_866_899_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_866_899_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_866_899_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">37</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClearMessage(NULL,&nbsp;TRUE);<br></span><span style="COLOR: #008080">38</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">39</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_TransRegedit&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br></span><span style="COLOR: #008080">40</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">41</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br></span><span style="COLOR: #008080">42</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;OnCancel();<br></span><span style="COLOR: #008080">43</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<img src ="http://www.cppblog.com/tgh621/aggbug/71782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2009-01-12 10:17 <a href="http://www.cppblog.com/tgh621/archive/2009/01/12/71782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 【转】字符串匹配算法（四）可以滑动多远</title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66596.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 05:09:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66596.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66596.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66596.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66596.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 记得在穷举法中，每一趟比较后，无论成与不成，都将模式向右滑动一个位置，然后继续比较。有没有办法能利用之前的比较结果，使得模式滑动的更远一点呢？在介绍经典的KMP算法前，我先介绍几个简单的滑动类算法。Not So Naive同名字一样，这个算法的确有点幼稚，它根据模式的前两个字符是否相同来滑动比穷举法稍长一点的距离：如果前两个字符相同，那么文本中与第二个字符不同则必然也与第一...&nbsp;&nbsp;<a href='http://www.cppblog.com/tgh621/archive/2008/11/11/66596.html'>阅读全文</a><img src ="http://www.cppblog.com/tgh621/aggbug/66596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 13:09 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 【转】字符串匹配算法（三）位运算的魔法——KR与SO</title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66595.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 05:08:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66595.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66595.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66595.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66595.html</trackback:ping><description><![CDATA[<div>位运算经常能做出一些不可思议的事情来，例如不用临时变量要交换两个数该怎么做呢？一个没接触过这类问题的人打死他也想不出来。如果拿围棋来做比喻，那么位运算可以喻为编程中的&#8220;手筋&#8221;。</div>
<div><br></div>
<div>按位的存储方式能提供最大的存储空间利用率，而随着空间被压缩的同时，由于CPU硬件的直接支持，速度竟然神奇般的提升了。举个例子，普通的数组要实现移位操作，那是O(n)的时间复杂度，而如果用位运算中的移位，就是一个指令搞定了。</div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">KR算法</span></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold"><br></span></div>
<div>KR算法之前第一章介绍中说是利用哈希，原文这么介绍的。而我的看法是，哈希只是一个幌子。这个算法的基本步骤同穷举法一样，不同在于每趟比较前先比较一下哈希值，hash值不同就不必比较了。而如果hash值无法高效计算，这样的改进甚至还不如不改进呢。你想想，比较之前还要先计算一遍hash值，有计算的功夫，直接比都比完了。</div>
<div><br></div>
<div>KR算法为了把挨个字符的比较转化为两个整数的比较，它把一个m长度的字符串直接当成一个整数来对待，以2为基数的整数。这样呢，在第一次算出这个整数后，以后每次移动窗口，只需要移去最高位，再加上最低位，就得出一个新的hash值。但是m太大，导致超出计算机所能处理的最大整数怎么办？不用担心，对整数最大值取模，借助模运算的特性，一切可以完美的进行。而且由于是对整数最大值取模，所以取模这一步都可以忽略掉。</div>
<div><br></div>
<div>这是KR算法的代码：</div>
<div>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><font color=#808080><span class=preprocessor>#define&nbsp;REHASH(a,&nbsp;b,&nbsp;h)&nbsp;((((h)&nbsp;-&nbsp;(a)*d)&nbsp;&lt;&lt;&nbsp;1)&nbsp;+&nbsp;(b))</span><span></span></font>
    <li class=alt><span></span>
    <li><span></span><span class=keyword><strong><font color=#0000ff>void</font></strong></span><span>&nbsp;KR(</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*y,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;n)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;d,&nbsp;hx,&nbsp;hy,&nbsp;i,&nbsp;j;</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Preprocessing&nbsp;*/</span><span></span></font>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>/*&nbsp;computes&nbsp;d&nbsp;=&nbsp;2^(m-1)&nbsp;with</font></span>
    <li class=alt><font color=#008200><span class=comment>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;left-shift&nbsp;operator&nbsp;*/</span><span></span></font>
    <li>&nbsp;&nbsp;&nbsp;<span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(d&nbsp;=&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;m;&nbsp;++i)</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;=&nbsp;(d&lt;&lt;1);</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(hy&nbsp;=&nbsp;hx&nbsp;=&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;m;&nbsp;++i)&nbsp;{</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hx&nbsp;=&nbsp;((hx&lt;&lt;1)&nbsp;+&nbsp;x[i]);</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hy&nbsp;=&nbsp;((hy&lt;&lt;1)&nbsp;+&nbsp;y[i]);</span>
    <li><span>&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><span></span>
    <li><span>&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Searching&nbsp;*/</span><span></span></font>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;j&nbsp;=&nbsp;0;</span>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>while</font></strong></span><span>&nbsp;(j&nbsp;&lt;=&nbsp;n-m)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(hx&nbsp;==&nbsp;hy&nbsp;&amp;&amp;&nbsp;memcmp(x,&nbsp;y&nbsp;+&nbsp;j,&nbsp;m)&nbsp;==&nbsp;0)</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT(j);</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hy&nbsp;=&nbsp;REHASH(y[j],&nbsp;y[j&nbsp;+&nbsp;m],&nbsp;hy);</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++j;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;}</span>
    <li><span></span>
    <li class=alt><span>}</span>
    <li><span></span>
    <li class=alt><span></span></li>
</ol>
</div>
我们可以看到，KR算法有O(m)复杂度的预处理的过程，总感觉它的预处理没有反映出模式本身的特点来，导致它的搜索过程依然是O(mn)复杂度的，只不过一般情况下体现不出来，在"aaaaaaaaaaaaaaaaaaaaaaaaa"中搜"aaaaa"就知道KR多慢了。</div>
<div><br></div>
<div>总的来说，KR算法比穷举强一点，比较次数的期望值是O(m+n)。</div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">Shift Or 算法</span></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold"><br></span></div>
<div>为了最大限度的发挥出位运算的能力，Shift Or算法就有了一个最大缺陷：模式不能超过机器字长。按现在普遍的32位机，机器字长就是32，也就是只能用来匹配不大于32个字符的模式。而带来的好处就是匹配过程是O(n)时间复杂度的，达到自动机的速度了。而预处理所花费的时间与空间都为O(m+&#963;)，比自动机少多了。</div>
<div><br></div>
<div>我们来看看它怎么巧妙的实现&#8220;只看一遍&#8221;的：</div>
<div><br></div>
<div>假设我们有一个升级系统，总共有m个级别。每一关都会放一个新人到第0级上，然后对于系统中所有的人，如果通过考验，升一级，否则，咔嚓掉。而对于升到最高级的人，那说明他连续通过了m次考验，这就是我们要选拔的人。</div>
<div><br></div>
<div>KR算法的思路就是上面的升级规则，给出的考验就是你的位置上的字符与给出的文本字符是否一致。升满级了，说明在连续m个位置上与不断给出的文本字符一致，这也就是匹配成功了。</div>
<div><br></div>
<div>明白了这个思路后，疑问就开始出来了：检查哪些位置与文本字符一致，需要m次吧？那么整个算法就是O(mn)了？</div>
<div><br></div>
<div>现在就该位运算出场了，对，这个算法的思路是很笨，但是我位运算的效率高呀，事先我算出字母表中每个字符在模式中出现的位置，用位的方式存在整数里，出现的地方标为0，不出现的地方标为1，这样总共使用&#963;个整数；同样，我用一个整数来表示升级状态，某个级别有人就标为0，没人就标为1，整个系统升级就恰好可以用&#8220;移位&#8221;来进行，当检查位置的时候只需要与表示状态的整数&#8220;或&#8221;1次，所以整个算法就成O(n)了。Shift-Or算法名字就是这样来的。</div>
<div><br></div>
<div>有一个地方很奇怪，0和1的设定和通常的习惯相反呀，习惯上，喜欢把存在设为1，不存在设为0的。不过这里没有办法，因为移位新移出来的是0。</div>
<div><br></div>
<div>这时我们来看代码就容易理解多了：</div>
<div>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><font color=#808080><span class=preprocessor>#define&nbsp;WORDSIZE&nbsp;sizeof(int)*8</span><span></span></font>
    <li><span class=Apple-style-span style="COLOR: rgb(128,128,128)">#define ASIZE 256</span>
    <li class=alt><span></span>
    <li><span></span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;preSo(</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;unsigned&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;S[])&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;j,&nbsp;lim;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;i;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;ASIZE;&nbsp;++i)</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S[i]&nbsp;=&nbsp;~0;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(lim&nbsp;=&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;m;&nbsp;++i,&nbsp;j&nbsp;&lt;&lt;=&nbsp;1)&nbsp;{</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S[x[i]]&nbsp;&amp;=&nbsp;~j;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lim&nbsp;|=&nbsp;j;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lim&nbsp;=&nbsp;~(lim&gt;&gt;1);</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>return</font></strong></span><span>(lim);</span>
    <li class=alt><span>}</span>
    <li><span></span>
    <li class=alt><span></span><span class=keyword><strong><font color=#0000ff>void</font></strong></span><span>&nbsp;SO(</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*y,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;n)&nbsp;{</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;lim,&nbsp;state;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;S[ASIZE];</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;j;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(m&nbsp;&gt;&nbsp;WORDSIZE)</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error(</span><span class=string><font color=#a31515>"SO:&nbsp;Use&nbsp;pattern&nbsp;size&nbsp;&lt;=&nbsp;word&nbsp;size"</font></span><span>);</span>
    <li class=alt><span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Preprocessing&nbsp;*/</span><span></span></font>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lim&nbsp;=&nbsp;preSo(x,&nbsp;m,&nbsp;S);</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Searching&nbsp;*/</span><span></span></font>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(state&nbsp;=&nbsp;~0,&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;n;&nbsp;++j)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state&nbsp;=&nbsp;(state&lt;&lt;1)&nbsp;|&nbsp;S[y[j]];</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(state&nbsp;&lt;&nbsp;lim)</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT(j&nbsp;-&nbsp;m&nbsp;+&nbsp;1);</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><span>}</span></li>
</ol>
</div>
</div>
代码中lim变量其实就是一个标尺，例如出现最高级的状态是01111111，那么lim就成了10000000，因此只要小于lim，就表示最高级上的0出现了。
<div><br></div>
<div>原文中对Shift-Or算法的描述还是很难懂的，如果对着那段说明去看代码，有点不知所云的感觉。我还是直接对着代码才想出这个升级的比喻来。</div>
<img src ="http://www.cppblog.com/tgh621/aggbug/66595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 13:08 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> [转]字符串匹配算法（二）穷举与自动机</title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66594.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 05:07:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66594.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66594.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66594.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66594.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66594.html</trackback:ping><description><![CDATA[穷举法又叫暴力法。大多数程序员眼里，它是幼稚的，但大师们不这么认为。
<div><br>
<div><span class=Apple-style-span style="COLOR: rgb(0,0,0); LINE-HEIGHT: 18px; FONT-FAMILY: Arial">Rob Pike, 最伟大的C 语言大师之一, 在《Notes on C Programming》中阐述了一个原则：</span><span class=Apple-style-span style="COLOR: rgb(0,0,0); LINE-HEIGHT: 18px; FONT-FAMILY: Arial">花哨的算法比简单算法更容易出bug、更难实现，尽量使用简单的算法配合简单的数据结构。而</span><span class=Apple-style-span style="COLOR: rgb(0,0,0); LINE-HEIGHT: 18px; FONT-FAMILY: Arial">Ken Thompson——Unix 最初版本的设计者和实现者，禅宗偈语般地对Pike 的这一原则作了强调：&nbsp;<span class=Apple-style-span style="FONT-WEIGHT: bold">拿不准就穷举（When in doubt , use brute force）</span>。&nbsp;而对于装13爱好者来说，更是自豪的称其使用的是BF算法。</span></div>
<div><br></div>
<div>穷举法用在字符串匹配上，简单的描述就是，检查文本从0到n-m的每一个位置，看看从这个位置开始是否与模式匹配。这种方法还是有一些优点的，如：不需要预处理过程，需要的额外空间为常数，每一趟比较时可以以任意顺序进行。<br></div>
<div><br></div>
<div>尽管它的时间复杂度为O(mn)，例如在文本"aaaaaaaaaaaaaaaaaaaaaaaaaaa"中寻找"aaaaab"时，就完全体现出来了。但是算法的期望值却是2n，这表明该算法在实际应用中效率不低。</div>
<div><br></div>
<div>C代码如下：</div>
<div>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><span class=keyword><strong><font color=#0000ff>void</font></strong></span><span>&nbsp;BF(</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*y,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;n)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;i,&nbsp;j;</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Searching&nbsp;*/</span><span></span></font>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;=&nbsp;n&nbsp;-&nbsp;m;&nbsp;++j)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;m&nbsp;&amp;&amp;&nbsp;x[i]&nbsp;==&nbsp;y[i&nbsp;+&nbsp;j];&nbsp;++i);</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(i&nbsp;&gt;=&nbsp;m)</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT(j);</span>
    <li><span>&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><span>}</span>
    <li><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
如果我们注意到C库函数是汇编优化过的，并通常能提供比C代码更高的性能的话，我们可以用memcmp来完成每一趟比较过程，从而达到更好的性能：</div>
<div>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><font color=#808080><span class=preprocessor>#define&nbsp;EOS&nbsp;'\0'</span><span></span></font>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#0000ff>void</font></strong></span><span>&nbsp;BF(</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*y,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;n)&nbsp;{&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*yb;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span><span class=comment><font color=#008200>/*&nbsp;Searching&nbsp;*/</font></span><span>&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(yb&nbsp;=&nbsp;y;&nbsp;*y&nbsp;!=&nbsp;EOS;&nbsp;++y)&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(memcmp(x,&nbsp;y,&nbsp;m)&nbsp;==&nbsp;0)&nbsp;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT(y&nbsp;-&nbsp;yb);</span>
    <li><span>}</span>
    <li class=alt><span></span>
    <li><span></span></li>
</ol>
</div>
自动机的方法其实和穷举法有点相似，都是用最简单直白的方式来做事情。区别在于穷举法是在计算，而自动机则是查表。尽管自动机的构造过程有一点点难解，要涉及到DFA的理论，但是自动机的比较过程那绝对是简单到无语。</div>
<div><br></div>
<div>简单说来，根据模式串，画好了一张大的表格，表格m+1行&#963;列，这里&#963;表示字母表的大小。表格每一行表示一种状态，状态数比模式长度多1。一开始的状态是0，也就是处在表格的第0行，这一行的每个元素指示了当遇到某字符时就跳转到另一个状态。每当跳转到最终状态时，表示找到了一个匹配。</div>
<div><br></div>
<div>语言表述起来还是比较啰嗦，看代码就知道了：</div>
<div>
<div class=highlighter>
<ol class=highlighter-cpp>
    <li><font color=#808080><span class=preprocessor>#define&nbsp;ASIZE&nbsp;256</span><span></span></font>
    <li class=alt><span></span>
    <li><span></span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;preAut(</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>*&nbsp;aut)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;i,&nbsp;state,&nbsp;target,&nbsp;old;</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(state&nbsp;=&nbsp;0,&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;m;&nbsp;++i)&nbsp;{</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target&nbsp;=&nbsp;i&nbsp;+&nbsp;1;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;old&nbsp;=&nbsp;aut[state&nbsp;*&nbsp;ASIZE&nbsp;+&nbsp;x[i]];</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;aut[state&nbsp;*&nbsp;ASIZE&nbsp;+&nbsp;x[i]]&nbsp;=&nbsp;target;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memcpy(aut&nbsp;+&nbsp;target&nbsp;*&nbsp;ASIZE,&nbsp;aut&nbsp;+&nbsp;old&nbsp;*&nbsp;ASIZE,&nbsp;ASIZE*</span><span class=keyword><strong><font color=#0000ff>sizeof</font></strong></span><span>(</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>));</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state&nbsp;=&nbsp;target;</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>return</font></strong></span><span>&nbsp;state;</span>
    <li class=alt><span>}</span>
    <li><span></span>
    <li class=alt><span></span>
    <li><span></span><span class=keyword><strong><font color=#0000ff>void</font></strong></span><span>&nbsp;AUT(</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*x,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;m,&nbsp;</span><span class=keyword><strong><font color=#0000ff>const</font></strong></span><span>&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>char</font></strong></span><span>&nbsp;*y,&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;n)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;j,&nbsp;state;</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Preprocessing&nbsp;*/</span><span></span></font>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;*aut&nbsp;=&nbsp;(</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>*)calloc((m+1)*ASIZE,&nbsp;</span><span class=keyword><strong><font color=#0000ff>sizeof</font></strong></span><span>(</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>));</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;Terminal&nbsp;=&nbsp;preAut(x,&nbsp;m,&nbsp;aut);</span>
    <li><span></span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><font color=#008200><span class=comment>/*&nbsp;Searching&nbsp;*/</span><span></span></font>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>for</font></strong></span><span>&nbsp;(state&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;n;&nbsp;++j)&nbsp;{</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state&nbsp;=&nbsp;aut[state*ASIZE+y[j]];</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#0000ff>if</font></strong></span><span>&nbsp;(state&nbsp;==&nbsp;Terminal)</span>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT(j&nbsp;-&nbsp;m&nbsp;+&nbsp;1);</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>
    <li class=alt><span>}</span></li>
</ol>
</div>
<div>（<span class=Apple-style-span style="COLOR: rgb(51,51,153)">注：原文的代码使用一个有向图的数据结构，我遵循大师的指引，改用了更简单一点的数组</span>）<br></div>
<div><br></div>
从代码上我们很容易看出，自动机的构造需要时间是O(m&#963;)，空间也是O(m&#963;)（严格来说这份代码使用了O((m+1)&#963;)），但是一旦构造完毕，接下来匹配的时间则是O(n)。</div>
<div><br></div>
<div>匹配的过程前面已经说了，太简单了没什么好说的，这里就解释一下构造过程吧！</div>
<div><br></div>
<div>我们构造的目标是对应模式长度，构造出同样多的状态，用0表示初始状态，然后第一个字符用状态1表示，第二个用状态2表示，依次类推，直到最后一个字符，用m表示，也是最终状态。</div>
<div><br></div>
<div>一开始，数组全都置0，，这个时候的自动机遇到任何字符都转到初始状态。然后给它看模式的第一个字符，假设这是'a'吧，告诉它，状态0遇到'a'应该到一个新的状态——状态1，所以把第0行的第'a'列修改为1。而这个时候状态1还是空白的，怎么办呢？</div>
<div><br></div>
<div>这时候状态0就想呀，在我被告知遇到'a'要去状态1之前，我原本遇到'a'都要去状态0的，也就是修改之前第'a'列所指的那个状态，称为old状态吧；而现在我遇到'a'却要去一个新的状态，既然以前old状态能处理遇到'a'之后的事情，那么我让新的状态像old状态一样就好了。于是状态0把old状态拷贝到状态1。</div>
<div><br></div>
<div>现在轮到状态1了，给它看第二个字符，它也如法炮制，指向了状态2，又把old状态拷贝给了状态2。</div>
<div><br></div>
<div>于是，状态机就在这种代代传承的过程中构造完毕了。</div>
<div><br></div>
<div>虽然理论上自动机是最完美的匹配方式，但是由于预处理的消耗过大，实践中，主要还是用于正则表达式。</div>
<div><br></div>
<div>结语：穷举法与自动机各自走了两个极端，因此都没能达到综合性能的最佳，本文之后介绍的算法，可以看成是在穷举和自动机两者之间取舍权衡的结果。</div>
</div>
<img src ="http://www.cppblog.com/tgh621/aggbug/66594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 13:07 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]字符串匹配算法（一）简介</title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66593.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 05:05:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66593.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66593.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66593.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66593.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66593.html</trackback:ping><description><![CDATA[<div>文本信息可以说是迄今为止最主要的一种信息交换手段，而作为文本处理中的一个重要领域——字符串匹配，就是我们今天要说的话题。（<span class=Apple-style-span style="COLOR: rgb(51,51,153)">原文还特意提及文本数据数量每18个月翻一番，以此论证算法必须要是高效的。不过我注意到摩尔定律也是18个月翻番，这正说明数据的增长是紧紧跟随处理速度的，因此越是使用高效的算法，将来待处理的数据就会越多。这也提示屏幕前的各位，代码不要写得太快了&#8230;&#8230;</span>）</div>
<div><br></div>
<div>字符串匹配指的是从文本中找出给定字符串（称为模式）的一个或所有出现的位置。本文的算法一律输出全部的匹配位置。模式串在代码中用x[m]来表示，文本用y[n]来，而所有字符串都构造自一个有限集的字母表&#931;，其大小为&#963;。</div>
<div><br></div>
<div>根据先给出模式还是先给出文本，字符串匹配分为两类方法：</div>
<div>
<ul>
    <li><span class=Apple-style-span style="LINE-HEIGHT: normal">第一类方法基于自动机或者字符串的组合特点，其实现上，通常是对模式进行预处理；</span><br>
    <li><span class=Apple-style-span style="LINE-HEIGHT: normal">第二类方法对文本建立索引，这也是现在搜索引擎采用的方法。</span></li>
</ul>
本文仅讨论第一类方法。<br></div>
<div><br></div>
<div>文中的匹配算法都是基于这样一种方式来进行的：设想一个长度为m的窗口，首先窗口的左端和文本的左端对齐，把窗口中的字符与模式字符进行比较，这称为一趟比较，当这一趟比较完全匹配或者出现失配时，将窗口向右移动。重复这个过程，直到窗口的右端到达了文本的右端。这种方法我们通常叫sliding window。</div>
<div><br></div>
<div>对于穷举法来说，找到所有匹配位置需要的时间为O(mn)，基于对穷举法改进的结果，我们按照每一趟比较时的比较顺序，把这些算法分为以下四种：</div>
<div>
<ol>
    <li>从左到右：最自然的方式，也是我们的阅读顺序
    <li>从右到左：通常在实践中能产生最好的算法
    <li>特殊顺序：可以达到理论上的极限
    <li>任意顺序：这些算法跟比较顺序没关系（例如：穷举法）</li>
</ol>
</div>
<div>一些主要算法的简单介绍如下：</div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">从左到右</span></div>
<div>采用哈希，可以很容易在大部分情况下避免二次比较，通过合理的假设，这种算法是线性时间复杂度的。它最先由Harrison提出，而后由Karp和Rabin全面分析，称为KR算法。</div>
<div>在假设模式长度不大于机器字长时，Shift-Or算法是很高效的匹配算法，同时它可以很容易扩展到模糊匹配上。</div>
<div>MP是第一个线性时间算法，随后被改进为KMP，它的匹配方式很类似于自动机的识别过程，文本的每个字符与模式的每个字符比较不会超过log<span class=Apple-style-span style="VERTICAL-ALIGN: sub">&#934;</span>(m+1)，这里&#934;是黄金分隔比1.618，而随后发现的类似算法——Simon算法，使得文本的每个字符比较不超过1+log<span class=Apple-style-span style="VERTICAL-ALIGN: sub">2</span>m，这三种算法在最坏情况下都只要2n-1次比较。（<span class=Apple-style-span style="COLOR: rgb(51,51,153)">抱歉限于我的水平这一段既没看懂也没能查证，大家就看个意思吧</span>）</div>
<div>基于确定性有限自动机的算法对文本字符刚好只用n次访问，但是它需要额外的<span class=Apple-style-span style="FONT-FAMILY: 'Times New Roman'">O(m&#963;)</span>的空间。</div>
<div>一种叫Forward Dawg Matching的算法同样也只用n次访问，它使用了模式的后缀自动机。</div>
<div>Apostolico-Crochemore算法是一种简单算法，最坏情况下也只需要3n/2次比较。<br></div>
<div>还有一种不那么幼稚（Not So Naive）的算法，最坏情况下是n平方，但是预处理过程的时间和空间均为常数，而且平均情况下的性能非常接近线性。</div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">从右到左</span></div>
<div>BM算法被认为是通常应用中最有效率的算法了，它或者它的简化版本常用于文本编辑器中的搜索和替换功能，对于非周期性的模式而言，3n是这种算法的比较次数上界了，不过对于周期性模式，它最坏情况下需要n的二次方。</div>
<div>BM算法的一些变种避免了原算法的二次方问题，比较高效的有：Apostolico and Giancarlo算法、Turbo BM算法和Reverse Colussi算法。</div>
<div>实验的结果表明，Quick Search算法（BM的一个变种）以及基于后缀自动机的Reverse Factor和Turbo Reverse Factor算法算是实践中最有效的算法了。<br></div>
<div>Zhu and Takaoka算法和BR算法也是BM的变种，它们则需要<span class=Apple-style-span style="FONT-FAMILY: 'Times New Roman'">O(&#963;</span><span class=Apple-style-span style="FONT-FAMILY: 'Times New Roman'"><span class=Apple-style-span style="VERTICAL-ALIGN: super">2</span></span><span class=Apple-style-span style="FONT-FAMILY: 'Times New Roman'">)</span>的额外空间。</div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">特殊顺序</span></div>
<div>最先达到空间线性最优的是Galil-Seiferas和Two Way算法，它们把模式分为两部分，先从左到右搜索右边的部分，如果没有失配，再搜索左边的部分。</div>
<div>Colussi和Galil-Giancarlo算法将模式位置分为两个子集，先从左至右搜索第一个子集，如果没有失配，再搜索剩下的。Colussi算法作为KMP算法的改进，使得最坏情况下只需要3n/2次比较，而Galil-Giancarlo算法则通过改进Colussi算法的一个特殊情况，把最坏比较次数减少到了4n/3。</div>
<div>最佳失配和M最大位移算法分别根据模式的字符频率和首字位移，对模式位置进行排序。<br></div>
<div>Skip Search，KMP Skip Search和Alpha Skip Search算法运用&#8220;桶&#8221;的方法来决定模式的起始位置。<br></div>
<div><br></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold">任意顺序</span></div>
<div><span class=Apple-style-span style="FONT-WEIGHT: bold"><span class=Apple-style-span style="FONT-WEIGHT: normal">Horspool算法也是BM的一个变种，它使用一种移位函数，而与字符比较顺序不相干。还有其他的变种如：</span><span class=Apple-style-span style="FONT-WEIGHT: normal">Quick Search算法，</span><span class=Apple-style-span style="FONT-WEIGHT: normal">Tuned Boyer-Moore算法，</span><span class=Apple-style-span style="FONT-WEIGHT: normal">Smith算法，</span><span class=Apple-style-span style="FONT-WEIGHT: normal">Raita算法。</span><br></span></div>
<div><br></div>
<div>在接下来的章节中，我们会给出上面这些算法的实现。我们把字母表限定为ASCII码或者它的任意子集，编程语言用C，这就意味着数组索引是从0开始，而字符串以NULL结尾。</div>
<div><br></div>
<div>（<span class=Apple-style-span style="COLOR: rgb(51,51,153)">第一章完。好像这些算法被挨个夸了个遍，反而不知道该选哪一种了，老外介绍别人的东西时就是这样，尽来虚的。</span>）</div>
<img src ="http://www.cppblog.com/tgh621/aggbug/66593.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 13:05 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66593.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么 char** 不能自动转化为 const char** (转) </title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 03:23:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66588.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66588.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66588.html</trackback:ping><description><![CDATA[<div class=postText>
<p>一次偶然的情况下我发现以下代码竟然无法被编译通过（如果你的编译器，比如VC6或VC2003，允许它编译通过，我想你首先应该换个编译器，比如GCC或VC2005）：<br><font color=#0000ff>void foo( <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* [] ) { }<br>int main( void )<br>{<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* s[2];<br>&nbsp;&nbsp;&nbsp; foo( s );<br>}</font><br>简化成更一般的形式是：<br><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p1 = 0;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p2 = p1;</font><br>错误是：<font color=#a52a2a>invalid conversion from `<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**' to `<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**'</font>.</p>
<p><a href="http://blog.vckbase.com/lostpencil" target=_blank><u><font color=#0066cc>lostpencil</font></u></a>更加仔细，使用C编译器给出的是一个警告：<br><font color=#a52a2a>initialization from incompatible pointer type</font>.</p>
<p>随后<a href="http://www.vckbase.com/bbs/userinfo.asp?id=hpho" target=_blank><u><font color=#0066cc>hpho</font></u></a>给出了合理的解释，同时<a href="http://groups.google.com/group/comp.lang.c++.moderated" target=_blank><u><font color=#0066cc>comp.lang.c++.moderated</font></u></a>上的<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#99;&#107;&#104;&#97;&#114;&#100;&#116;&#64;&#115;&#97;&#116;&#111;&#114;&#108;&#97;&#115;&#101;&#114;&#46;&#99;&#111;&#109;"><u><font color=#0066cc>Ulrich Eckhardt</font></u></a>也用代码进行了说明。</p>
<p>用代码来说明最直观了：<br><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* s = "abc";<br>int main( void )<br>{<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* p0 = 0;<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p1 = &amp;p0;<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p2 = p1;</font> // 先假设这一句是合法的 ( 测试时，可以先强制类型<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">转</strong>化一下 )<br><font color=#0000ff>&nbsp;&nbsp;&nbsp; *p2 = s;<br>&nbsp;&nbsp;&nbsp; *p0 = 'A';</font> // 通过p0在修改不应该被修改的s，这显然和<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong>相违背，其运行结果不可知。<br><font color=#0000ff>}<br><br><br><br><br></font></p>
</div>
<p><font color=#0000ff>看了 **的 想到的<br>tekyDec 29, 2005 -&nbsp; Show original item </font></p>
<p><font color=#0000ff>看完后.明白**讲的为什么<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** 不能自动<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">转</strong>化为 <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**,(原文)但对我影响最深的是下面的话:</font></p>
<p><font color=#0000ff>==================================================================<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p="abc" 能不能编译通过要看你使用的编译器。鉴于大量遗留代码的存在，大部分编译器允许其通过，或者给个警告。当然，程序员自己必须保证绝不去修改其值。 </font></p>
<p><font color=#0000ff>程序员不应该在代码中出现*p='A'这样的语句。这是当初约定好了的：编译器允许<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p="abc"通过，而程序员保证不去修改它。 <br>b. *p='A'编译时应该允许通过，因为单就这条语句而言，它完全合法。 <br>c. 运行时*p='A'能不能通过要看实际的运行环境，包括你使用的操作系统、编译器、编译器选项 等等，一句话，其运行结果由不得你，且不应该由你去关心，因为这种行为本身已经违反约定了。 <br>==================================================================</font></p>
<p><font color=#0000ff>工作关系吧,用CString 和string用的太多了,很少这样定义字符串 <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;了<br>匝一看,还不适应,:(,渐渐的回想才想起一些来(哎,还是太生疏,赶快写下来,以后别忘了)</font></p>
<p><font color=#0000ff>这样定义的字符串<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220; ; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p1=&#8220;123445667&#8220;;</font></p>
<p><font color=#0000ff>正如上面提到的是不能再 *p='A',运行的时候会出错,同样,strcpy(p,p1)也会出错哟,</font></p>
<p><font color=#0000ff>"abcde"字符串可以看做是个常量字符串了,是不能被修改的,</font></p>
<p><font color=#0000ff>但如果 <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p[]=&#8220;abcde&#8220; 这样定义,就没有问题,你可以修改*p='A',只要不越界就ok.</font></p>
<p><font color=#0000ff>并且发现这样两种定义<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;</font></p>
<p><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p[]=&#8220;abcde&#8220; </font></p>
<p><font color=#0000ff>在运行的时候,p指向的地址也不是一样的,可见<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;还是有特殊的处理 :),具体怎么处理就不知道了,高手请指教:)</font></p>
<font color=#0000ff></font>
<p><font color=#0000ff><br>随着测试,又发现个问题,可能是个老问题了吧:</font></p>
<p><font color=#0000ff><br>int main(int argc, <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* argv[])<br>{ <br>&nbsp;int t[10];<br>&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p1[7]="123456";<br>&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p2="1234567890123213123";<br>&nbsp;<br>&nbsp;int len(0);<br>&nbsp;<br>&nbsp; //*p1='C';&nbsp; err</font></p>
<p><font color=#0000ff>&nbsp;len=strlen(p1);<br>&nbsp;printf("%d\n",len);<br>&nbsp;<br>&nbsp;strcpy(p1,p2);&nbsp;&nbsp; ///??????????<br>&nbsp;<br>&nbsp;printf("%s\n",p1);<br>&nbsp;<br>&nbsp;len=strlen(p1);<br>&nbsp;<br>&nbsp;printf("%d\n",len);<br>&nbsp;return 0;<br>}</font></p>
<p><font color=#0000ff>我定义的是7个字符数组, 但用strcpy把p2拷到p1中,p1是放不下的,但程序却正常执行,warning ,err都没有,运行也正常?</font></p>
<p><font color=#0000ff><br>输出 </font></p>
<p><font color=#0000ff>6<br>1234567890123213123<br>19</font></p>
<p><font color=#0000ff>应该是使用内存越界了阿??怎么会正常运行呢?</font></p>
<p><font color=#0000ff>难道对于内存越界的使用,运气好才崩溃表现出来,运气不好就正常运行??</font></p>
<p class=postfoot>posted on 2006-02-22 13:04 <a href="http://www.blogjava.net/Vencent/"><u><font color=#0066cc>Vincent.Chen</font></u></a> 阅读(232) <a href="http://cache.baidu.com/c?m=9d78d513d9921cf319ab837e7c478d35594380122ba1d5020ca7870fd33a541b0120a1ac26510d199680397001d81902b7a56e21735037b7ec94df0cc0ffc5747edf7b726d4fc607498247f88a5b24c22b965dfeaf6ebdfcaf6c&amp;p=90769a4086cc41ae1fb2c528510c&amp;user=b#Post"><u><font color=#0066cc>评论(0)</font></u></a> &nbsp;<a href="http://www.blogjava.net/Vencent/admin/EditArticles.aspx?postid=31945"><u><font color=#0066cc>编辑</font></u></a> &nbsp;<a href="http://www.blogjava.net/Vencent/AddToFavorite.aspx?id=31945"><u><font color=#0066cc>收藏</font></u></a> 所属分类: <a href="http://www.blogjava.net/Vencent/category/5790.html"><u><font color=#0066cc>杂</font></u></a></p>
<img src ="http://www.cppblog.com/tgh621/aggbug/66588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 11:23 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ 转]C++类型转换符的使用 </title><link>http://www.cppblog.com/tgh621/archive/2008/09/27/62926.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Sat, 27 Sep 2008 10:13:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/27/62926.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62926.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/27/62926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62926.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62926.html</trackback:ping><description><![CDATA[<p>C++的四个类型转换运算符已经有很久了,但一直没有弄清楚它们的用法,今天看到一本书上的解释,才大致地的了解了其具体的用法.</p>
<p>具体归纳如下:</p>
<p><span style="COLOR: red"><strong>reinterpret_cast</strong></span></p>
<p>该函数将一个类型的指针转换为另一个类型的指针.<br>这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.<br>reinterpret_cast 可以将指针值转换为一个整型数,但不能用于非指针类型的转换.<br>例:<br>//基本类型指针的类型转换<br>double d=9.2;<br>double* pd = &amp;d;<br>int *pi = reinterpret_cast&lt;int*&gt;(pd);&nbsp; //相当于int *pi = (int*)pd;</p>
<p>//不相关的类的指针的类型转换<br>class A{};<br>class B{};<br>A* pa = new A;<br>B* pb = reinterpret_cast&lt;B*&gt;(pa);&nbsp;&nbsp; //相当于B* pb = (B*)pa;</p>
<p>//指针转换为整数<br>long l = reinterpret_cast&lt;long&gt;(pi);&nbsp;&nbsp; //相当于long l = (long)pi;</p>
<p><br><span style="COLOR: red"><strong>const_cast</strong></span></p>
<p>该函数用于去除指针变量的常量属性，将它转换为一个对应指针类型的普通变量。反过来，也可以将一个非常量的指针变量转换为一个常指针变量。<br>这种转换是在编译期间做出的类型更改。<br>例：<br>const int* pci = 0;<br>int* pk = const_cast&lt;int*&gt;(pci);&nbsp; //相当于int* pk = (int*)pci;</p>
<p>const A* pca = new A;<br>A* pa = const_cast&lt;A*&gt;(pca);&nbsp;&nbsp;&nbsp;&nbsp; //相当于A* pa = (A*)pca;</p>
<p>出于安全性考虑，const_cast无法将非指针的常量转换为普通变量。</p>
<p><br><span style="COLOR: red"><strong>static_cast</strong></span></p>
<p>该函数主要用于基本类型之间和具有继承关系的类型之间的转换。<br>这种转换一般会更改变量的内部表示方式，因此，static_cast应用于指针类型转换没有太大意义。<br>例：<br>//基本类型转换<br>int i=0;<br>double d = static_cast&lt;double&gt;(i);&nbsp; //相当于 double d = (double)i;</p>
<p>//转换继承类的对象为基类对象<br>class Base{};<br>class Derived : public Base{};<br>Derived d;<br>Base b = static_cast&lt;Base&gt;(d);&nbsp;&nbsp;&nbsp;&nbsp; //相当于 Base b = (Base)d;</p>
<p><br><span style="COLOR: red"><strong>dynamic_cast</strong></span></p>
<p>它与static_cast相对，是动态转换。<br>这种转换是在运行时进行转换分析的，并非在编译时进行，明显区别于上面三个类型转换操作。<br>该函数只能在继承类对象的指针之间或引用之间进行类型转换。进行转换时，会根据当前运行时类型信息，判断类型对象之间的转换是否合法。dynamic_cast的指针转换失败，可通过是否为null检测，引用转换失败则抛出一个bad_cast异常。<br>例：<br>class Base{};<br>class Derived : public Base{};</p>
<p>//派生类指针转换为基类指针<br>Derived *pd = new Derived;<br>Base *pb = dynamic_cast&lt;Base*&gt;(pd);</p>
<p>if (!pb)<br>&nbsp;cout &lt;&lt; "类型转换失败" &lt;&lt; endl;</p>
<p>//没有继承关系，但被转换类有虚函数<br>class A(virtual ~A();)&nbsp;&nbsp; //有虚函数<br>class B{}:<br>A* pa = new A;<br>B* pb&nbsp; = dynamic_cast&lt;B*&gt;(pa);</p>
<p>如果对无继承关系或者没有虚函数的对象指针进行转换、基本类型指针转换以及基类指针转换为派生类指针，都不能通过编译。<br></p>
<img src ="http://www.cppblog.com/tgh621/aggbug/62926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-27 18:13 <a href="http://www.cppblog.com/tgh621/archive/2008/09/27/62926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UNICODE串转换成char类型串的四种方法[转]</title><link>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Sat, 27 Sep 2008 10:11:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62924.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62924.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62924.html</trackback:ping><description><![CDATA[<p>1. 调用 WideCharToMultiByte() API</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;WideCharToMultiByte&nbsp;(<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;&nbsp;&nbsp;&nbsp;CodePage,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">1&nbsp;Unicode编码的字符页，Unicode编码有字符页的概念，比如gb2312/936，big5/950等</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;dwFlags,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">2&nbsp;如何处理复合unicode字符，详细查google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPCWSTR&nbsp;lpWideCharStr,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">3&nbsp;待转换的unicode串</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cchWideChar,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">4&nbsp;表示参数3的长度&nbsp;&nbsp;传递-1表示以0x00结尾</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPSTR&nbsp;&nbsp;&nbsp;lpMultiByteStr,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">5&nbsp;接受转换后的串的字符缓冲</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbMultiByte,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">6&nbsp;表示参数5lpMutiByteStr的字节大小&nbsp;通常sizeof一下</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPCSTR&nbsp;&nbsp;lpDefaultChar,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">7&nbsp;NULL&nbsp;具体google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPBOOL&nbsp;&nbsp;lpUsedDefaultChar</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">8&nbsp;NULL&nbsp;具体google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>2. 调用CRT函数wcstombs()</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">size_t&nbsp;wcstombs&nbsp;(<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mbstr,<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;wchar_t</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;wcstr,<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count&nbsp;);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>3. 使用CString构造器或赋值操作</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;假设有一个Unicode串wszSomeString<img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>CString&nbsp;str1&nbsp;(&nbsp;wszSomeString&nbsp;);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用构造器转换</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">CString&nbsp;str2;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>str2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;wszSomeString;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用赋值操作转换</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>4. 使用ATL串转换宏</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">atlconv.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;还是假设有一个Unicode串wszSomeString<img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_58_177_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_58_177_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_58_177_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_58_177_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_58_177_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_58_177_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_58_177_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_58_177_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_58_177_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_58_177_Open_Text><span style="COLOR: #000000">{<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;szANSIString&nbsp;[MAX_PATH];<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;USES_CONVERSION;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;声明这个宏要使用的局部变量</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;lstrcpy&nbsp;(&nbsp;szANSIString,&nbsp;OLE2A(wszSomeString)&nbsp;);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br></span></div>
<img src ="http://www.cppblog.com/tgh621/aggbug/62924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-27 18:11 <a href="http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++虚函数表解析(转) </title><link>http://www.cppblog.com/tgh621/archive/2008/09/18/62212.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Thu, 18 Sep 2008 10:54:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/18/62212.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62212.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/18/62212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62212.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62212.html</trackback:ping><description><![CDATA[<div class=postText>
<p>C++中的虚函数的作用主要是实现了多态的机制。关于多态，简而言之就是用父类型别的指针指向其子类的实例，然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有&#8220;多种形态&#8221;，这是一种泛型技术。所谓泛型技术，说白了就是试图使用不变的代码来实现可变的算法。比如：模板技术，RTTI技术，虚函数技术，要么是试图做到在编译时决议，要么试图做到运行时决议。
<p>关于虚函数的使用方法，我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中，我只想从虚函数的实现机制上面为大家 一个清晰的剖析。
<p>当然，相同的文章在网上也出现过一些了，但我总感觉这些文章不是很容易阅读，大段大段的代码，没有图片，没有详细的说明，没有比较，没有举一反三。不利于学习和阅读，所以这是我想写下这篇文章的原因。也希望大家多给我提意见。
<p>言归正传，让我们一起进入虚函数的世界。
<h3>虚函数表</h3>
<p>对C++ 了解的人都应该知道虚函数（Virtual Function）是通过一张虚函数表（Virtual Table）来实现的。简称为V-Table。 在这个表中，主是要一个类的虚函数的地址表，这张表解决了继承、覆盖的问题，保证其容真实反应实际的函数。这样，在有虚函数的类的实例中这个表被分配在了 这个实例的内存中，所以，当我们用父类的指针来操作一个子类的时候，这张虚函数表就显得由为重要了，它就像一个地图一样，指明了实际所应该调用的函数。
<p>这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到，编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置（这是为了保证正确取到虚函数的偏移量）。 这意味着我们通过对象实例的地址得到这张虚函数表，然后就可以遍历其中函数指针，并调用相应的函数。
<p>听我扯了那么多，我可以感觉出来你现在可能比以前更加晕头转向了。 没关系，下面就是实际的例子，相信聪明的你一看就明白了。
<p>假设我们有这样的一个类：
<p>class Base {
<p>public:
<p>virtual void f() { cout &lt;&lt; "Base::f" &lt;&lt; endl; }
<p>virtual void g() { cout &lt;&lt; "Base::g" &lt;&lt; endl; }
<p>virtual void h() { cout &lt;&lt; "Base::h" &lt;&lt; endl; }
<p>};
<p>按照上面的说法，我们可以通过Base的实例来得到虚函数表。 下面是实际例程：
<p>typedef void(*Fun)(void);
<p>Base b;
<p>Fun pFun = NULL;
<p>cout &lt;&lt; "虚函数表地址：" &lt;&lt; (int*)(&amp;b) &lt;&lt; endl;
<p>cout &lt;&lt; "虚函数表 — 第一个函数地址：" &lt;&lt; (int*)*(int*)(&amp;b) &lt;&lt; endl;
<p>// Invoke the first virtual function
<p>pFun = (Fun)*((int*)*(int*)(&amp;b));
<p>pFun();
<p>实际运行经果如下：(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
<p>虚函数表地址：0012FED4
<p>虚函数表 — 第一个函数地址：0044F148
<p>Base::f
<p>通过这个示例，我们可以看到，我们可以通过强行把&amp;b转成int *，取得虚函数表的地址，然后，再次取址就可以得到第一个虚函数的地址了，也就是Base::f()，这在上面的程序中得到了验证（把int* 强制转成了函数指针）。通过这个示例，我们就可以知道如果要调用Base::g()和Base::h()，其代码如下：
<p>(Fun)*((int*)*(int*)(&amp;b)+0); // Base::f()
<p>(Fun)*((int*)*(int*)(&amp;b)+1); // Base::g()
<p>(Fun)*((int*)*(int*)(&amp;b)+2); // Base::h()
<p>这个时候你应该懂了吧。什么？还是有点晕。也是，这样的代码看着太乱了。没问题，让我画个图解释一下。如下所示：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable1.jpg" border=0>
<p>注意：在上面这个图中，我在虚函数表的最后多加了一个结点，这是虚函数表的结束结点，就像字符串的结束符&#8220;\0&#8221;一样，其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在WinXP+VS2003下，这个值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下，这个值是如果1，表示还有下一个虚函数表，如果值是0，表示是最后一个虚函数表。
<p>下面，我将分别说明&#8220;无覆盖&#8221;和&#8220;有覆盖&#8221;时的虚函数表的样子。没有覆盖父类的虚函数是毫无意义的。我之所以要讲述没有覆盖的情况，主要目的是为了给一个对比。在比较之下，我们可以更加清楚地知道其内部的具体实现。
<h3>一般继承（无虚函数覆盖）</h3>
<p>下面，再让我们来看看继承时的虚函数表是什么样的。假设有如下所示的一个继承关系：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing3.jpg" border=0>
<p>请注意，在这个继承关系中，子类没有重载任何父类的函数。那么，在派生类的实例中，其虚函数表如下所示：
<p>对于实例：Derive d; 的虚函数表如下：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable2.JPG" border=0>
<p>我们可以看到下面几点：
<p>1）虚函数按照其声明顺序放于表中。
<p>2）父类的虚函数在子类的虚函数前面。
<p>我相信聪明的你一定可以参考前面的那个程序，来编写一段程序来验证。
<h3>一般继承（有虚函数覆盖）</h3>
<p>覆盖父类的虚函数是很显然的事情，不然，虚函数就变得毫无意义。下面，我们来看一下，如果子类中有虚函数重载了父类的虚函数，会是一个什么样子？假设，我们有下面这样的一个继承关系。
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing4.jpg" border=0>
<p>为了让大家看到被继承过后的效果，在这个类的设计中，我只覆盖了父类的一个函数：f()。那么，对于派生类的实例，其虚函数表会是下面的一个样子：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable3.JPG" border=0>
<p>我们从表中可以看到下面几点，
<p>1）覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
<p>2）没有被覆盖的函数依旧。
<p>这样，我们就可以看到对于下面这样的程序，
<p>Base *b = new Derive();
<p>b-&gt;f();
<p>由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代，于是在实际调用发生时，是Derive::f()被调用了。这就实现了多态。
<h3>多重继承（无虚函数覆盖）</h3>
<p>下面，再让我们来看看多重继承中的情况，假设有下面这样一个类的继承关系。注意：子类并没有覆盖父类的函数。
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing1.jpg" border=0>
<p>对于子类实例中的虚函数表，是下面这个样子：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable4.JPG" border=0>
<p>我们可以看到：
<p>1） 每个父类都有自己的虚表。
<p>2） 子类的成员函数被放到了第一个父类的表中。（所谓的第一个父类是按照声明顺序来判断的）
<p>这样做就是为了解决不同的父类类型的指针指向同一个子类实例，而能够调用到实际的函数。
<h3>多重继承（有虚函数覆盖）</h3>
<p>下面我们再来看看，如果发生虚函数覆盖的情况。
<p>下图中，我们在子类中覆盖了父类的f()函数。
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing2.jpg" border=0>
<p>下面是对于子类实例中的虚函数表的图：
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable5.jpg" border=0>
<p>我们可以看见，三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样，我们就可以任一静态类型的父类来指向子类，并调用子类的f()了。如：
<p>Derive d;
<p>Base1 *b1 = &amp;d;
<p>Base2 *b2 = &amp;d;
<p>Base3 *b3 = &amp;d;
<p>b1-&gt;f(); //Derive::f()
<p>b2-&gt;f(); //Derive::f()
<p>b3-&gt;f(); //Derive::f()
<p>b1-&gt;g(); //Base1::g()
<p>b2-&gt;g(); //Base2::g()
<p>b3-&gt;g(); //Base3::g()
<h3>安全性</h3>
<p>每次写C++的文章，总免不了要批判一下C++。这篇文章也不例外。通过上面的讲述，相信我们对虚函数表有一个比较细致的了解了。水可载舟，亦可覆舟。下面，让我们来看看我们可以用虚函数表来干点什么坏事吧。
<p><strong>一、通过父类型的指针访问子类自己的虚函数</strong>
<p>我们知道，子类没有重载父类的虚函数是一件毫无意义的事情。因为多态也是要基于函数重载的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数，但我们根本不可能使用下面的语句来调用子类的自有虚函数：
<p>Base1 *b1 = new Derive();
<p>b1-&gt;f1(); //编译出错
<p>任何妄图使用父类指针想调用子类中的<strong>未覆盖父类的成员函数</strong>的行为都会被编译器视为非法，所以，这样的程序根本无法编译通过。但在运行时，我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。（关于这方面的尝试，通过阅读后面附录的代码，相信你可以做到这一点）
<p><strong>二、访问non-public</strong><strong>的虚函数</strong>
<p>另外，如果父类的虚函数是private或是protected的，但这些非public的虚函数同样会存在于虚函数表中，所以，我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数，这是很容易做到的。
<p>如：
<p>class Base {
<p>private:
<p>virtual void f() { cout &lt;&lt; "Base::f" &lt;&lt; endl; }
<p>};
<p>class Derive : public Base{
<p>};
<p>typedef void(*Fun)(void);
<p>void main() {
<p>Derive d;
<p>Fun pFun = (Fun)*((int*)*(int*)(&amp;d)+0);
<p>pFun();
<p>}
<h3>结束语</h3>
<p>C++这门语言是一门Magic的语言，对于程序员来说，我们似乎永远摸不清楚这门语言背着我们在干了什么。需要熟悉这门语言，我们就必需要了解C++里面的那些东西，需要去了解C++中那些危险的东西。不然，这是一种搬起石头砸自己脚的编程语言。</p>
</div>
<img src ="http://www.cppblog.com/tgh621/aggbug/62212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-18 18:54 <a href="http://www.cppblog.com/tgh621/archive/2008/09/18/62212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>