﻿<?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>BlogJava-分享JAVA的快乐-随笔分类-B)   C++ </title><link>http://www.blogjava.net/bcims/category/7095.html</link><description>----------------------------------------------我有一分快乐，分享一份给你，也希望你能快乐！</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:37:47 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:37:47 GMT</pubDate><ttl>60</ttl><item><title>C++之python函数调用 </title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28356.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 12:04:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28356.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28356.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28356.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28356.html</trackback:ping><description><![CDATA[<DIV class=postText>
<P><BR><BR>代码如下，分别演示直接执行python语句、无返回无参数函数调用、返回单参数函数调用。返回多参数函数调用：<BR><BR>#include &lt;Python.h&gt;<BR>#include &lt;iostream&gt;<BR>using namespace std;</P>
<P>//执行python命令<BR>void ExecPythonCommand()<BR>{<BR>&nbsp;//直接执行<BR>&nbsp;PyRun_SimpleString("from time import time,ctime\n"<BR>&nbsp;&nbsp;"print 'Today is',ctime(time())\n");<BR>}</P>
<P>//调用无参数函数<BR>void InvokeNoParm()<BR>{<BR>&nbsp;PyObject*&nbsp;pMod&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pFunc&nbsp;= NULL;<BR>&nbsp;//导入模块<BR>&nbsp;pMod = PyImport_ImportModule("Life");<BR>&nbsp;if(pMod)<BR>&nbsp;{<BR>&nbsp;&nbsp;//获取函数地址<BR>&nbsp;&nbsp;pFunc = PyObject_GetAttrString(pMod, "a");<BR>&nbsp;&nbsp;if(pFunc)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;//函数调用<BR>&nbsp;&nbsp;&nbsp;PyEval_CallObject(pFunc, NULL);<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;cout &lt;&lt; "cannot find function a" &lt;&lt; endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;cout &lt;&lt; "cannot find Life.py" &lt;&lt; endl;<BR>&nbsp;}<BR>}</P>
<P>//调用一参数函数<BR>void InvokeWith1Parm()<BR>{<BR>&nbsp;PyObject*&nbsp;pMod&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pFunc&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pParm&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pRetVal&nbsp;= NULL;<BR>&nbsp;int&nbsp;&nbsp;&nbsp;iRetVal&nbsp;= 0;<BR>&nbsp;//导入模块<BR>&nbsp;pMod = PyImport_ImportModule("FuncDef");<BR>&nbsp;if(pMod)<BR>&nbsp;{<BR>&nbsp;&nbsp;pFunc = PyObject_GetAttrString(pMod, "square");<BR>&nbsp;&nbsp;if(pFunc)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;//创建参数<BR>&nbsp;&nbsp;&nbsp;pParm = Py_BuildValue("(i)", 5);<BR>&nbsp;&nbsp;&nbsp;//函数调用<BR>&nbsp;&nbsp;&nbsp;pRetVal = PyEval_CallObject(pFunc, pParm);<BR>&nbsp;&nbsp;&nbsp;//解析返回值<BR>&nbsp;&nbsp;&nbsp;PyArg_Parse(pRetVal, "i", &amp;iRetVal);<BR>&nbsp;&nbsp;&nbsp;cout &lt;&lt; "square 5 is: " &lt;&lt; iRetVal &lt;&lt; endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;cout &lt;&lt; "cannot find function square" &lt;&lt; endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;cout &lt;&lt; "cannot find FuncDef.py" &lt;&lt; endl;<BR>&nbsp;}<BR>}</P>
<P>//调用多参数函数<BR>void InvokeWith2Parm()<BR>{<BR>&nbsp;PyObject*&nbsp;pMod&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pFunc&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pParm&nbsp;= NULL;<BR>&nbsp;PyObject*&nbsp;pRetVal&nbsp;= NULL;<BR>&nbsp;int&nbsp;&nbsp;&nbsp;iRetVal&nbsp;= 0;<BR>&nbsp;//导入模块<BR>&nbsp;pMod = PyImport_ImportModule("add");<BR>&nbsp;if(pMod)<BR>&nbsp;{<BR>&nbsp;&nbsp;pFunc = PyObject_GetAttrString(pMod, "add");<BR>&nbsp;&nbsp;if(pFunc)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;//创建两个参数<BR>&nbsp;&nbsp;&nbsp;pParm = PyTuple_New(2);<BR>&nbsp;&nbsp;&nbsp;//为参数赋值<BR>&nbsp;&nbsp;&nbsp;PyTuple_SetItem(pParm, 0, Py_BuildValue("i",2000));<BR>&nbsp;&nbsp;&nbsp;PyTuple_SetItem(pParm, 1, Py_BuildValue("i",3000));<BR>&nbsp;&nbsp;&nbsp;//函数调用<BR>&nbsp;&nbsp;&nbsp;pRetVal = PyEval_CallObject(pFunc, pParm);<BR>&nbsp;&nbsp;&nbsp;//解析返回值<BR>&nbsp;&nbsp;&nbsp;PyArg_Parse(pRetVal, "i", &amp;iRetVal);<BR>&nbsp;&nbsp;&nbsp;cout &lt;&lt; "2000 + 3000 = " &lt;&lt; iRetVal &lt;&lt; endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;cout &lt;&lt; "cannot find function square" &lt;&lt; endl;<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;cout &lt;&lt; "cannot find add.py" &lt;&lt; endl;<BR>&nbsp;}<BR>}</P>
<P>int main(int argc, char* argv[])<BR>{<BR>&nbsp;Py_Initialize();&nbsp;//python 解释器的初始化<BR>&nbsp;<BR>&nbsp;ExecPythonCommand();<BR>&nbsp;InvokeNoParm();<BR>&nbsp;InvokeWith1Parm();<BR>&nbsp;InvokeWith2Parm();</P>
<P>&nbsp;Py_Finalize();&nbsp;&nbsp;// 垃圾回收、清除导入库<BR>&nbsp;return 0;<BR>}<BR><BR><BR>习惯C＋＋的内存分配释放，突然间不用释放，感觉很蹊跷，上网查发现也没有释放函数。如果真这样的话，是很可怕的，因为无法自己管理内存，但是我相信编译器作者的垃圾回收机制，所以OK，不管！！<BR><BR><A href="http://www.cppblog.com/Files/wlwlxj/InvokePython.rar">代码下载</A></P></DIV><img src ="http://www.blogjava.net/bcims/aggbug/28356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 20:04 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有么办法可以得到基类的地址?? </title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28355.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 12:03:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28355.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28355.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28355.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28355.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28355.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"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;BaseA<BR><IMG id=Codehighlighter1_12_80_Open_Image onclick="this.style.display='none'; Codehighlighter1_12_80_Open_Text.style.display='none'; Codehighlighter1_12_80_Closed_Image.style.display='inline'; Codehighlighter1_12_80_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_12_80_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_12_80_Closed_Text.style.display='none'; Codehighlighter1_12_80_Open_Image.style.display='inline'; Codehighlighter1_12_80_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_12_80_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_12_80_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">:<BR><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FuncA1()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FuncA2()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;BaseB<BR><IMG id=Codehighlighter1_96_162_Open_Image onclick="this.style.display='none'; Codehighlighter1_96_162_Open_Text.style.display='none'; Codehighlighter1_96_162_Closed_Image.style.display='inline'; Codehighlighter1_96_162_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_96_162_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_96_162_Closed_Text.style.display='none'; Codehighlighter1_96_162_Open_Image.style.display='inline'; Codehighlighter1_96_162_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_96_162_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_96_162_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">:<BR><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FunB1()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FunB2()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000">;<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Sample&nbsp;:&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;BaseA,</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;BaseB<BR><IMG id=Codehighlighter1_207_457_Open_Image onclick="this.style.display='none'; Codehighlighter1_207_457_Open_Text.style.display='none'; Codehighlighter1_207_457_Closed_Image.style.display='inline'; Codehighlighter1_207_457_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_207_457_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_207_457_Closed_Text.style.display='none'; Codehighlighter1_207_457_Open_Image.style.display='inline'; Codehighlighter1_207_457_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_207_457_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_207_457_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">:<BR><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FuncA1()<BR><IMG id=Codehighlighter1_243_279_Open_Image onclick="this.style.display='none'; Codehighlighter1_243_279_Open_Text.style.display='none'; Codehighlighter1_243_279_Closed_Image.style.display='inline'; Codehighlighter1_243_279_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_243_279_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_243_279_Closed_Text.style.display='none'; Codehighlighter1_243_279_Open_Image.style.display='inline'; Codehighlighter1_243_279_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_243_279_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_243_279_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">BaseA::FuncA1</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">endl;<BR><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><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FuncA2()<BR><IMG id=Codehighlighter1_307_343_Open_Image onclick="this.style.display='none'; Codehighlighter1_307_343_Open_Text.style.display='none'; Codehighlighter1_307_343_Closed_Image.style.display='inline'; Codehighlighter1_307_343_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_307_343_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_307_343_Closed_Text.style.display='none'; Codehighlighter1_307_343_Open_Image.style.display='inline'; Codehighlighter1_307_343_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_307_343_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_307_343_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">BaseA::FuncA2</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">endl;<BR><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><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FunB1()<BR><IMG id=Codehighlighter1_370_399_Open_Image onclick="this.style.display='none'; Codehighlighter1_370_399_Open_Text.style.display='none'; Codehighlighter1_370_399_Closed_Image.style.display='inline'; Codehighlighter1_370_399_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_370_399_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_370_399_Closed_Text.style.display='none'; Codehighlighter1_370_399_Open_Image.style.display='inline'; Codehighlighter1_370_399_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_370_399_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_370_399_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">BaseB1</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">endl;<BR><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><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">virtual</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;FunB2()<BR><IMG id=Codehighlighter1_426_455_Open_Image onclick="this.style.display='none'; Codehighlighter1_426_455_Open_Text.style.display='none'; Codehighlighter1_426_455_Closed_Image.style.display='inline'; Codehighlighter1_426_455_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_426_455_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_426_455_Closed_Text.style.display='none'; Codehighlighter1_426_455_Open_Image.style.display='inline'; Codehighlighter1_426_455_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_426_455_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_426_455_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">BaseB2</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">endl;<BR><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><IMG src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000">;</SPAN></DIV>&nbsp;&nbsp;&nbsp;&nbsp;你们有什么方法可以求出基类的地址,这个问题现在阻碍我下一篇文章的发表,我尝试的N多方法,发现思路不正确,我们可以一起来解决这个问题.... <img src ="http://www.blogjava.net/bcims/aggbug/28355.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 20:03 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28355.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>收集的部分C++经典书籍 </title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28353.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 12:02:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28353.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28353.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28353.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28353.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28353.html</trackback:ping><description><![CDATA[<DIV class=postText><SPAN id=yuyuzi>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt"><FONT face=宋体>C++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt"><FONT face=宋体>历史：<SPAN lang=EN-US>C++</SPAN>源于<SPAN lang=EN-US>C</SPAN>语言，而<SPAN lang=EN-US>C</SPAN>语言是在<SPAN lang=EN-US>B</SPAN>语言的基础上发展起来的。</FONT><FONT face=宋体><SPAN lang=EN-US> <BR>--1960</SPAN>年出现了一种面向问题的高级语言<SPAN lang=EN-US>ALGOL 60 </SPAN>。</FONT><SPAN lang=EN-US><BR><FONT face=宋体>--1963</FONT></SPAN><FONT face=宋体>年英国剑桥大学推出了<SPAN lang=EN-US>CPL</SPAN>（<SPAN lang=EN-US>Combined Programming Language</SPAN>）语言，后来经简化为<SPAN lang=EN-US>BCPL</SPAN>语言。</FONT><FONT face=宋体><SPAN lang=EN-US> <BR><BR><BR>--1970</SPAN>年美国贝尔<SPAN lang=EN-US>[Bell]</SPAN>实验室的<SPAN lang=EN-US>K.Thompson</SPAN>以<SPAN lang=EN-US>BCPL</SPAN>语言为基础，设计了一种类似于<SPAN lang=EN-US>BCPL</SPAN>的语言，取其第一字母<SPAN lang=EN-US>B</SPAN>，称为<SPAN lang=EN-US>B</SPAN>语言。<SPAN lang=EN-US> --1972</SPAN>年美国贝尔实验室的<SPAN lang=EN-US>Dennis M.Ritchie</SPAN>为克服<SPAN lang=EN-US>B</SPAN>语言的诸多不足，在<SPAN lang=EN-US>B</SPAN>语言的基础上重新设计了一种语言，取其第二字母<SPAN lang=EN-US>C</SPAN>，故称为<SPAN lang=EN-US>C</SPAN>语言。</FONT><FONT face=宋体><SPAN lang=EN-US> <BR>--1980</SPAN>年贝尔实验室的<SPAN lang=EN-US>Bjarne Stroustrup</SPAN>对<SPAN lang=EN-US>C</SPAN>语言进行了扩充，推出了<SPAN lang=EN-US>“</SPAN>带类的<SPAN lang=EN-US>C”</SPAN>，多次修改后起名为<SPAN lang=EN-US>C++</SPAN>。以后又经过不断的改进，发展成为今天的<SPAN lang=EN-US>C++</SPAN>。<SPAN lang=EN-US><?xml:namespace prefix = o /><o:p></o:p></SPAN></FONT></SPAN></P>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt"></SPAN><FONT face=宋体 size=2>C++</FONT></SPAN><FONT face=宋体><SPAN style="FONT-SIZE: 10pt">拥有丰富的历史，是许多程序员通往高阶的楼梯，也是许多高校计算机专业和程序爱好者的首选语言。这里我收集了一些<SPAN lang=EN-US>C++</SPAN>相关的书籍，每一本都是<SPAN lang=EN-US>C++</SPAN>开发中的经典教程。部分链接在教育网内更容易下载，大家可以继续补充。</SPAN></FONT></P>
<P></P>
<P><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Effective C++ </FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>中文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://dlb.pchome.net/development/reference/effectiveCplus.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Effective C++ </FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>中文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>--</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>候捷翻译</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.nethovel.com/resources/Essential%20C%2B%2B%D6%D0%CE%C4%B0%E6%28%C8%AB%29.rar"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>More Effective C++ </FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>中文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>--</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>候捷翻译</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.nethovel.com/resources/MoreEffectiveC%2B%2B%28WQ%29.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>数据结构</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>语言描述中文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.code-labs.com/manual/c_c015.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>标准库英文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://166.111.64.4/incoming/%D0%C2%CE%C4%BC%FE%BC%D0/f/The%20C%2B%2B%20Standard%20Library%28with%20TOC%29.pdf"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++ Primer</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>英文版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://computerstep.w18.net/C/C%2B%2B%20Primer.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>编程思想</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; <A href="http://www.dingbing.com/book/thinkc.zip"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Thinking in C++ 2nd Edition&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.nethovel.com/resources/ThinkinginC%2B%2B.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>The C++ Programming Language&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://computerstep.w18.net/C/The%20C%2B%2B%20Programming%20Language.rar"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Inside C++ Object Model(</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>深度探索</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>对象模型）</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>--</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>候捷翻译</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.jka77.com/book/inside-the-cpp-object-model.pdf"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>STL</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>源码剖析</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>--</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>候捷翻译</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; <A href="ftp://ftp.math.nankai.edu.cn/Ebook/C_C%2B%2B/STL%D4%B4%C2%EB%C6%CA%CE%F6--%BA%EE%BD%DD.pdf"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><BR></FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>程序设计实践</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://ftp.math.nankai.edu.cn/Ebook/China-pub/chinapub_computerscience_multimedia/%B3%CC%D0%F2%C9%E8%BC%C6%CA%B5%BC%F9/"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链<SPAN lang=EN-US>接</SPAN></SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Com</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>技术内幕</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.helpwork.com/book/html/user/download.asp?id=1123"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Com+</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>技术内幕</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.helpwork.com/book/html/user/download.asp?id=952"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>Windows</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>网络编程</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>(</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>第</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>2</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>)&nbsp; </FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>链接</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><BR>Windows2000</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>编程技术内幕</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>(By Mickey Williams) </FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>机械工业出版社</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://ftp.frontfree.net/Pub/Books/C&amp;C%2B%2B/VC/Windows2000%B1%E0%B3%CC%BC%BC%CA%F5%C4%DA%C4%BB.rar"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>C++ Builder</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>高级编程技术</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="http://www.dingbing.com/book/builder.zip"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>VC++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>技术内幕第四版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>(</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>潘爱民</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>)&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://210.32.157.56/%BF%CE%BC%FE/c%2B%2Bprimer/vc%2B%2B%BC%BC%CA%F5%C4%DA%C4%BBIV%28%C5%CB%B0%AE%C3%F1%29.rar"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>VC++</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>技术内幕第五版</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; <A href="http://www.helpwork.com/downdata/book/programming/vc/book/vc%2B%2B2/invcpp5.chm"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR>TCP-IP</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>详解卷</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>1</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>：协议</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://202.204.4.161/%D1%A7%CF%B0%D7%CA%C1%CF/TCPIP/TCP-IP%CF%EA%BD%E2%BE%ED1%A3%BA%D0%AD%D2%E9.pdf"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>TCP-IP</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>详解卷</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>2</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>：实现</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://202.204.4.161/%D1%A7%CF%B0%D7%CA%C1%CF/TCPIP/TCP-IP%CF%EA%BD%E2%BE%ED3%A3%BATCP%CA%C2%CE%F1%D0%AD%D2%E9%A3%ACHTTP%A3%ACNNTP.pdf"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A><BR></FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>TCP-IP</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>详解卷</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>3</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>：</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>TCP</FONT></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><FONT size=2>事物协议</FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2>&nbsp; </FONT></SPAN><SPAN lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><FONT size=2><A href="ftp://202.204.4.161/%D1%A7%CF%B0%D7%CA%C1%CF/TCPIP/TCP-IP%CF%EA%BD%E2%BE%ED2%A3%BA%CA%B5%CF%D6.pdf"><SPAN lang=EN-US style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体"><SPAN lang=EN-US>链接</SPAN></SPAN></A></FONT></SPAN></P></DIV><img src ="http://www.blogjava.net/bcims/aggbug/28353.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 20:02 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28353.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的变量交换</title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28354.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 12:02:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28354.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28354.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28354.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28354.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28354.html</trackback:ping><description><![CDATA[<BR><BR>在程序学习之中我们会遇到一些经典的问题如交换两个变量的值。现在我要求不用第三个变量<BR>来对其进行交换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代码如下：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<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; HEIGHT: 292px; 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: #000000">#include</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">iostream.h</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;main()<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_33_217_Open_Image onclick="this.style.display='none'; Codehighlighter1_33_217_Open_Text.style.display='none'; Codehighlighter1_33_217_Closed_Image.style.display='inline'; Codehighlighter1_33_217_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_33_217_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_33_217_Closed_Text.style.display='none'; Codehighlighter1_33_217_Open_Image.style.display='inline'; Codehighlighter1_33_217_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN id=Codehighlighter1_33_217_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_33_217_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">23</SPAN><SPAN style="COLOR: #000000">;<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;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;Number2&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">33</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><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;cout</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">Number1</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">\n</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">Number2</SPAN><SPAN style="COLOR: #000000">&lt;&lt;</SPAN><SPAN style="COLOR: #000000">endl;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><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;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">^</SPAN><SPAN style="COLOR: #000000">&nbsp;Number2;<BR></SPAN><SPAN style="COLOR: #008080">11</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;Number2&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">^</SPAN><SPAN style="COLOR: #000000">&nbsp;Number2;<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;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Number1&nbsp;</SPAN><SPAN style="COLOR: #000000">^</SPAN><SPAN style="COLOR: #000000">&nbsp;Number2;<BR></SPAN><SPAN style="COLOR: #008080">13</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;<NUMBER1<<"\N"<<NUMBER2<<ENDL;<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;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">15</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">16</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>&nbsp;&nbsp;&nbsp;&nbsp; ^的关系图<BR>&nbsp;&nbsp;&nbsp; 0 ^ 0&nbsp; = 0;<BR>&nbsp;&nbsp;&nbsp; 0 ^ 1&nbsp; = 1;<BR>&nbsp;&nbsp;&nbsp; 1 ^ 0&nbsp; = 1;<BR>&nbsp;&nbsp;&nbsp; 1 ^ 1&nbsp; = 0; <img src ="http://www.blogjava.net/bcims/aggbug/28354.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 20:02 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28354.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>屏幕截图工具V1[附源码] </title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28352.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 12:01:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28352.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28352.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28352.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28352.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28352.html</trackback:ping><description><![CDATA[<BR><BR>前段时间仿照QQ的截图工具，我也做了一个。有很多朋友跟我索要源码，今天就把它放了上来供大家参考:)。原理其实很简单，需要了解的可以下源码看一下。如果你改进后，请不要忘记给我也发一份<IMG height=19 src="http://www.cppblog.com/Emoticons/teeth_smile.gif" width=19 border=0> <BR><BR>使用步骤： <BR>1）点[Capture]按钮进入截图状态 <BR>2）在屏幕上用按住鼠标左键拖动一个矩形 <BR>3）双击鼠标左键或按[Enter]键，结束 <BR>4）此时返回到上图界面，按[Save]保存图像。或者直接Ctr+C至Word…… <BR><BR>取消选择的矩形：单击右键 <BR><BR><IMG alt="" src="http://mythma.bokee.com/inc/sc011.bmp"><BR><BR><A href="http://mythma.bokee.com/inc/ScreenCapture1.rar">可执行文件</A><BR><BR><A href="http://www.cppblog.com/Files/mythma/ScreenCapture_src1.01.rar">源码下载</A><BR><BR><A class=postTitle2 id=viewpost1_TitleUrl href="http://www.cppblog.com/mythma/archive/2005/11/17/1176.html"><FONT color=#4371a6>屏幕截图DIY</FONT></A> <BR><img src ="http://www.blogjava.net/bcims/aggbug/28352.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 20:01 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28352.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++风格与技巧</title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28340.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 11:53:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28340.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28340.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28340.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28340.html</trackback:ping><description><![CDATA[<BR><BR>
<P align=left>（译注：本文的翻译相当艰苦。Bjarne Stroustrup不愧是创立C++语言的一代大师，不但思想博大精深，而且在遣词造句上，也非常精微深奥。有很多地方，译者反复斟酌，都不能取得理想的效果，只能尽力而为。 
<P>Html格式的文档见译者主页：http://www.wushuang.net</P>
<P>如果你对这个翻译稿有任何意见和建议，请发信给译者：onekey@163.com。</P>
<P>原文的地址为：http://www.research.att.com/~bs/bs_faq.html）</P>
<P></P>
<P>（Bjarne Stroustrup博士，1950年出生于丹麦，先后毕业于丹麦阿鲁斯大学和英国剑挢大学，AT&amp;T大规模程序设计研究部门负责人，AT&amp;T 贝尔实验室和ACM成员。1979年，B. S开始开发一种语言，当时称为"C with Class"，后来演化为C++。1998年，ANSI/ISO C++标准建立，同年，B. S推出其经典著作The C++ Programming Language的第三版。）</P>
<P></P>
<P>这是一些人们经常向我问起的有关C++的风格与技巧的问题。如果你能提出更好的问题，或者对这些答案有所建议，请务必发Email给我(bs@research.att.com)。请记住，我不能把全部的时间都花在更新我的主页上面。</P>
<P></P>
<P>更多的问题请参见我的general FAQ。</P>
<P></P>
<P>关于术语和概念，请参见我的C++术语表（C++ glossary.）。</P>
<P></P>
<P>请注意，这仅仅是一个常见问题与解答的列表。它不能代替一本优秀教科书中那些经过精心挑选的范例与解释。它也不能象一本参考手册或语言标准那样，提供详细和准确的说明。有关C++的设计的问题，请参见《C++语言的设计和演变》（The Design and Evolution of C++）。关于C++语言与标准库的使用，请参见《C++程序设计语言》（The C++ Programming Language）。</P>
<P></P>
<P>目录：</P>
<P>我如何写这个非常简单的程序？</P>
<P>为什么编译要花这么长的时间？</P>
<P>为什么一个空类的大小不为0？</P>
<P>我必须在类声明处赋予数据吗？</P>
<P>为什么成员函数默认不是virtual的？</P>
<P>为什么析构函数默认不是virtual的？</P>
<P>为什么不能有虚拟构造函数？</P>
<P>为什么重载在继承类中不工作？</P>
<P>我能够在构造函数中调用一个虚拟函数吗？</P>
<P>有没有“指定位置删除”(placement delete)？</P>
<P>我能防止别人继承我自己的类吗？</P>
<P>为什么不能为模板参数定义约束（constraints）？</P>
<P>既然已经有了优秀的qsort()函数，为什么还需要一个sort()？</P>
<P>什么是函数对象（function object）？</P>
<P>我应该如何对付内存泄漏？</P>
<P>我为什么在捕获一个异常之后就不能继续？</P>
<P>为什么C++中没有相当于realloc()的函数？</P>
<P>如何使用异常？</P>
<P>怎样从输入中读取一个字符串？</P>
<P>为什么C++不提供“finally”的构造？</P>
<P>什么是自动指针（auto_ptr），为什么没有自动数组（auto_array）？</P>
<P>可以混合使用C风格与C++风格的内存分派与重新分配吗？</P>
<P>我为什么必须使用一个造型来转换*void？</P>
<P>我如何定义一个类内部（in-class）的常量？</P>
<P>为什么delete不会将操作数置0？</P>
<P>我能够写“void main()”吗？</P>
<P>为什么我不能重载点符号，::，sizeof，等等？</P>
<P>怎样将一个整型值转换为一个字符串？</P>
<P>“int* p”正确还是“int *p”正确？</P>
<P>对于我的代码，哪一种布局风格（layout style）是最好的？</P>
<P>我应该将“const”放在类型之前还是之后？</P>
<P>使用宏有什么问题？</P>
<P></P>
<P>我如何写这个非常简单的程序？</P>
<P></P>
<P>特别是在一个学期的开始，我常常收到许多关于编写一个非常简单的程序的询问。这个问题有一个很具代表性的解决方法，那就是（在你的程序中）读入几个数字，对它们做一些处理，再把结果输出。下面是一个这样做的例子：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;vector&gt;</P>
<P>#include&lt;algorithm&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>vector&lt;double&gt; v;</P>
<P></P>
<P>double d;</P>
<P>while(cin&gt;&gt;d) v.push_back(d); // 读入元素</P>
<P>if (!cin.eof()) { // 检查输入是否出错</P>
<P>cerr &lt;&lt; "format error\n";</P>
<P>return 1; // 返回一个错误</P>
<P>}</P>
<P></P>
<P>cout &lt;&lt; "read " &lt;&lt; v.size() &lt;&lt; " elements\n";</P>
<P></P>
<P>reverse(v.begin(),v.end());</P>
<P>cout &lt;&lt; "elements in reverse order:\n";</P>
<P>for (int i = 0; i&lt;v.size(); ++i) cout &lt;&lt; v[i] &lt;&lt; '\n';</P>
<P></P>
<P>return 0; // 成功返回</P>
<P>}</P>
<P></P>
<P>对这段程序的观察：</P>
<P></P>
<P>这是一段标准的ISO C++程序，使用了标准库(standard library)。标准库工具在命名空间std中声明，封装在没有.h后缀的头文件中。</P>
<P></P>
<P>如果你要在Windows下编译它，你需要将它编译成一个“控制台程序”（console application）。记得将源文件加上.cpp后缀，否则编译器可能会以为它是一段C代码而不是C++。</P>
<P></P>
<P>是的，main()函数返回一个int值。</P>
<P></P>
<P>读到一个标准的向量(vector)中，可以避免在随意确定大小的缓冲中溢出的错误。读到一个数组(array)中，而不产生“简单错误”(silly error)，这已经超出了一个新手的能力——如果你做到了，那你已经不是一个新手了。如果你对此表示怀疑，我建议你阅读我的文章“将标准C++作为一种新的语言来学习”("Learning Standard C++ as a New Language")，你可以在本人著作列表(my publications list)中下载到它。</P>
<P></P>
<P>!cin.eof()是对流的格式的检查。事实上，它检查循环是否终结于发现一个end-of-file(如果不是这样，那么意味着输入没有按照给定的格式)。更多的说明，请参见你的C++教科书中的“流状态”(stream state)部分。</P>
<P></P>
<P>vector知道它自己的大小，因此我不需要计算元素的数量。</P>
<P></P>
<P>这段程序没有包含显式的内存管理。Vector维护一个内存中的栈，以存放它的元素。当一个vector需要更多的内存时，它会分配一些；当它不再生存时，它会释放内存。于是，使用者不需要再关心vector中元素的内存分配和释放问题。</P>
<P></P>
<P>程序在遇到输入一个“end-of-file”时结束。如果你在UNIX平台下运行它，“end-of-file”等于键盘上的Ctrl+D。如果你在Windows平台下，那么由于一个BUG它无法辨别“end-of-file”字符，你可能倾向于使用下面这个稍稍复杂些的版本，它使用一个词“end”来表示输入已经结束。</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;vector&gt;</P>
<P>#include&lt;algorithm&gt;</P>
<P>#include&lt;string&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>vector&lt;double&gt; v;</P>
<P></P>
<P>double d;</P>
<P>while(cin&gt;&gt;d) v.push_back(d); // 读入一个元素</P>
<P>if (!cin.eof()) { // 检查输入是否失败</P>
<P>cin.clear(); // 清除错误状态</P>
<P>string s;</P>
<P>cin &gt;&gt; s; // 查找结束字符</P>
<P>if (s != "end") {</P>
<P>cerr &lt;&lt; "format error\n";</P>
<P>return 1; // 返回错误</P>
<P>}</P>
<P>}</P>
<P></P>
<P>cout &lt;&lt; "read " &lt;&lt; v.size() &lt;&lt; " elements\n";</P>
<P></P>
<P>reverse(v.begin(),v.end());</P>
<P>cout &lt;&lt; "elements in reverse order:\n";</P>
<P>for (int i = 0; i&lt;v.size(); ++i) cout &lt;&lt; v[i] &lt;&lt; '\n';</P>
<P></P>
<P>return 0; // 成功返回</P>
<P>}</P>
<P></P>
<P>更多的关于使用标准库将事情简化的例子，请参见《C++程序设计语言》中的“漫游标准库”("Tour of the Standard Library")一章。</P>
<P></P>
<P>为什么编译要花这么长的时间？</P>
<P></P>
<P>你的编译器可能有问题。也许它太老了，也许你安装它的时候出了错，也许你用的计算机已经是个古董。在诸如此类的问题上，我无法帮助你。</P>
<P></P>
<P>但是，这也是很可能的：你要编译的程序设计得非常糟糕，以至于编译器不得不检查数以百计的头文件和数万行代码。理论上来说，这是可以避免的。如果这是你购买的库的设计问题，你对它无计可施（除了换一个更好的库），但你可以将你自己的代码组织得更好一些，以求得将修改代码后的重新编译工作降到最少。这样的设计会更好，更有可维护性，因为它们展示了更好的概念上的分离。</P>
<P></P>
<P>看看这个典型的面向对象的程序例子：</P>
<P></P>
<P>class Shape {</P>
<P>public: // 使用Shapes的用户的接口</P>
<P>virtual void draw() const;</P>
<P>virtual void rotate(int degrees);</P>
<P>// ...</P>
<P>protected: // common data (for implementers of Shapes)</P>
<P>Point center;</P>
<P>Color col;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class Circle : public Shape {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int) { }</P>
<P>// ...</P>
<P>protected:</P>
<P>int radius;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class Triangle : public Shape {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int);</P>
<P>// ...</P>
<P>protected:</P>
<P>Point a, b, c;</P>
<P>// ...</P>
<P>}; </P>
<P></P>
<P>设计思想是，用户通过Shape的public接口来操纵它们，而派生类（例如Circle和Triangle）的实现部分则共享由protected成员表现的那部分实现（implementation）。</P>
<P></P>
<P>这不是一件容易的事情：确定哪些实现部分是对所有的派生类都有用的，并将之共享出来。因此，与public接口相比，protected成员往往要做多得多的改动。举例来说，虽然理论上“中心”(center)对所有的图形都是一个有效的概念，但当你要维护一个三角形的“中心”的时候，是一件非常麻烦的事情——对于三角形，当且仅当它确实被需要的时候，计算这个中心才是有意义的。</P>
<P></P>
<P>protected成员很可能要依赖于实现部分的细节，而Shape的用户（译注：user此处译为用户，指使用Shape类的代码，下同）却不见得必须依赖它们。举例来说，很多（大多数？）使用Shape的代码在逻辑上是与“颜色”无关的，但是由于Shape中“颜色”这个定义的存在，却可能需要一堆复杂的头文件，来结合操作系统的颜色概念。</P>
<P></P>
<P>当protected部分发生了改变时，使用Shape的代码必须重新编译——即使只有派生类的实现部分才能够访问protected成员。</P>
<P></P>
<P>于是，基类中的“实现相关的信息”(information helpful to implementers)对用户来说变成了象接口一样敏感的东西，它的存在导致了实现部分的不稳定，用户代码的无谓的重编译（当实现部分发生改变时），以及将头文件无节制地包含进用户代码中（因为“实现相关的信息”需要它们）。有时这被称为“脆弱的基类问题”(brittle base class problem)。</P>
<P></P>
<P>一个很明显的解决方案就是，忽略基类中那些象接口一样被使用的“实现相关的信息”。换句话说，使用接口，纯粹的接口。也就是说，用抽象基类的方式来表示接口：</P>
<P></P>
<P>class Shape {</P>
<P>public: //使用Shapes的用户的接口</P>
<P>virtual void draw() const = 0;</P>
<P>virtual void rotate(int degrees) = 0;</P>
<P>virtual Point center() const = 0;</P>
<P>// ...</P>
<P></P>
<P>// 没有数据</P>
<P>};</P>
<P></P>
<P>class Circle : public Shape {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int) { }</P>
<P>Point center() const { return center; }</P>
<P>// ...</P>
<P>protected:</P>
<P>Point cent;</P>
<P>Color col;</P>
<P>int radius;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class Triangle : public Shape {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int);</P>
<P>Point center() const;</P>
<P>// ...</P>
<P>protected:</P>
<P>Color col;</P>
<P>Point a, b, c;</P>
<P>// ...</P>
<P>}; </P>
<P></P>
<P>现在，用户代码与派生类的实现部分的变化之间的关系被隔离了。我曾经见过这种技术使得编译的时间减少了几个数量级。</P>
<P></P>
<P>但是，如果确实存在着对所有派生类（或仅仅对某些派生类）都有用的公共信息时怎么办呢？可以简单把这些信息封装成类，然后从它派生出实现部分的类：</P>
<P></P>
<P>class Shape {</P>
<P>public: //使用Shapes的用户的接口</P>
<P>virtual void draw() const = 0;</P>
<P>virtual void rotate(int degrees) = 0;</P>
<P>virtual Point center() const = 0;</P>
<P>// ...</P>
<P></P>
<P>// no data</P>
<P>};</P>
<P></P>
<P>struct Common {</P>
<P>Color col;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class Circle : public Shape, protected Common {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int) { }</P>
<P>Point center() const { return center; }</P>
<P>// ...</P>
<P>protected:</P>
<P>Point cent;</P>
<P>int radius;</P>
<P>};</P>
<P></P>
<P>class Triangle : public Shape, protected Common {</P>
<P>public: </P>
<P>void draw() const;</P>
<P>void rotate(int);</P>
<P>Point center() const;</P>
<P>// ...</P>
<P>protected:</P>
<P>Point a, b, c;</P>
<P>}; </P>
<P></P>
<P>为什么一个空类的大小不为0？</P>
<P></P>
<P>要清楚，两个不同的对象的地址也是不同的。基于同样的理由，new总是返回指向不同对象的指针。</P>
<P>看看：</P>
<P></P>
<P>class Empty { };</P>
<P></P>
<P>void f()</P>
<P>{</P>
<P>Empty a, b;</P>
<P>if (&amp;a == &amp;b) cout &lt;&lt; "impossible: report error to compiler supplier";</P>
<P></P>
<P>Empty* p1 = new Empty;</P>
<P>Empty* p2 = new Empty;</P>
<P>if (p1 == p2) cout &lt;&lt; "impossible: report error to compiler supplier";</P>
<P>} </P>
<P></P>
<P>有一条有趣的规则：一个空的基类并不一定有分隔字节。</P>
<P>struct X : Empty {</P>
<P>int a;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>void f(X* p)</P>
<P>{</P>
<P>void* p1 = p;</P>
<P>void* p2 = &amp;p-&gt;a;</P>
<P>if (p1 == p2) cout &lt;&lt; "nice: good optimizer";</P>
<P>}</P>
<P></P>
<P>这种优化是允许的，可以被广泛使用。它允许程序员使用空类以表现一些简单的概念。现在有些编译器提供这种“空基类优化”(empty base class optimization)。</P>
<P></P>
<P>我必须在类声明处赋予数据吗？</P>
<P></P>
<P>不必须。如果一个接口不需要数据时，无须在作为接口定义的类中赋予数据。代之以在派生类中给出它们。参见“为什么编译要花这么长的时间？”。</P>
<P></P>
<P>有时候，你必须在一个类中赋予数据。考虑一下复数类的情况：</P>
<P></P>
<P>template&lt;class Scalar&gt; class complex {</P>
<P>public:</P>
<P>complex() : re(0), im(0) { }</P>
<P>complex(Scalar r) : re(r), im(0) { }</P>
<P>complex(Scalar r, Scalar i) : re(r), im(i) { }</P>
<P>// ...</P>
<P></P>
<P>complex&amp; operator+=(const complex&amp; a)</P>
<P>{ re+=a.re; im+=a.im; return *this; }</P>
<P>// ...</P>
<P>private:</P>
<P>Scalar re, im;</P>
<P>};</P>
<P></P>
<P>设计这种类型的目的是将它当做一个内建（built-in）类型一样被使用。在声明处赋值是必须的，以保证如下可能：建立真正的本地对象（genuinely local objects）(比如那些在栈中而不是在堆中分配的对象)，或者使某些简单操作被适当地inline化。对于那些支持内建的复合类型的语言来说，要获得它们提供的效率，真正的本地对象和inline化都是必要的。</P>
<P></P>
<P>为什么成员函数默认不是virtual的？</P>
<P></P>
<P>因为很多类并不是被设计作为基类的。例如复数类。</P>
<P></P>
<P>而且，一个包含虚拟函数的类的对象，要占用更多的空间以实现虚拟函数调用机制——往往是每个对象占用一个字(word)。这个额外的字是非常可观的，而且在涉及和其它语言的数据的兼容性时，可能导致麻烦(例如C或Fortran语言)。</P>
<P></P>
<P>要了解更多的设计原理，请参见《C++语言的设计和演变》（The Design and Evolution of C++）。</P>
<P></P>
<P>为什么析构函数默认不是virtual的？</P>
<P></P>
<P>因为很多类并不是被设计作为基类的。只有类在行为上是它的派生类的接口时(这些派生类往往在堆中分配，通过指针或引用来访问)，虚拟函数才有意义。</P>
<P></P>
<P>那么什么时候才应该将析构函数定义为虚拟呢？当类至少拥有一个虚拟函数时。拥有虚拟函数意味着一个类是派生类的接口，在这种情况下，一个派生类的对象可能通过一个基类指针来销毁。例如：</P>
<P></P>
<P>class Base {</P>
<P>// ...</P>
<P>virtual ~Base();</P>
<P>};</P>
<P></P>
<P>class Derived : public Base {</P>
<P>// ...</P>
<P>~Derived();</P>
<P>};</P>
<P></P>
<P>void f()</P>
<P>{</P>
<P>Base* p = new Derived;</P>
<P>delete p; // 虚拟析构函数保证~Derived函数被调用</P>
<P>}</P>
<P></P>
<P>如果基类的析构函数不是虚拟的，那么派生类的析构函数将不会被调用——这可能产生糟糕的结果，例如派生类的资源不会被释放。</P>
<P></P>
<P>为什么不能有虚拟构造函数？</P>
<P></P>
<P>虚拟调用是一种能够在给定信息不完全(given partial information)的情况下工作的机制。特别地，虚拟允许我们调用某个函数，对于这个函数，仅仅知道它的接口，而不知道具体的对象类型。但是要建立一个对象，你必须拥有完全的信息。特别地，你需要知道要建立的对象的具体类型。因此，对构造函数的调用不可能是虚拟的。</P>
<P></P>
<P>当要求建立一个对象时，一种间接的技术常常被当作“虚拟构造函数”来使用。有关例子，请参见《C++程序设计语言》第三版15.6.2.节。</P>
<P></P>
<P>下面这个例子展示一种机制：如何使用一个抽象类来建立一个适当类型的对象。</P>
<P></P>
<P>struct F { // 对象建立函数的接口</P>
<P>virtual A* make_an_A() const = 0;</P>
<P>virtual B* make_a_B() const = 0;</P>
<P>};</P>
<P></P>
<P>void user(const F&amp; fac)</P>
<P>{</P>
<P>A* p = fac.make_an_A(); // 将A作为合适的类型</P>
<P>B* q = fac.make_a_B(); // 将B作为合适的类型</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>struct FX : F {</P>
<P>A* make_an_A() const { return new AX(); } // AX是A的派生</P>
<P>B* make_a_B() const { return new BX(); } // AX是B的派生</P>
<P>};</P>
<P></P>
<P>struct FY : F {</P>
<P>A* make_an_A() const { return new AY(); } // AY是A的派生</P>
<P>B* make_a_B() const { return new BY(); } // BY是B的派生</P>
<P></P>
<P>};</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>user(FX()); // 此用户建立AX与BX</P>
<P>user(FY()); // 此用户建立AY与BY</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>这是所谓的“工厂模式”(the factory pattern)的一个变形。关键在于，user函数与AX或AY这样的类的信息被完全分离开来了。</P>
<P></P>
<P>为什么重载在继承类中不工作？</P>
<P></P>
<P>这个问题（非常常见）往往出现于这样的例子中：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>class B {</P>
<P>public:</P>
<P>int f(int i) { cout &lt;&lt; "f(int): "; return i+1; }</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class D : public B {</P>
<P>public:</P>
<P>double f(double d) { cout &lt;&lt; "f(double): "; return d+1.3; }</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>D* pd = new D;</P>
<P></P>
<P>cout &lt;&lt; pd-&gt;f(2) &lt;&lt; '\n';</P>
<P>cout &lt;&lt; pd-&gt;f(2.3) &lt;&lt; '\n';</P>
<P>}</P>
<P></P>
<P>它输出的结果是：</P>
<P></P>
<P>f(double): 3.3</P>
<P>f(double): 3.6</P>
<P></P>
<P>而不是象有些人猜想的那样：</P>
<P></P>
<P>f(int): 3</P>
<P>f(double): 3.6</P>
<P></P>
<P>换句话说，在B和D之间并没有发生重载的解析。编译器在D的区域内寻找，找到了一个函数double f(double)，并执行了它。它永远不会涉及（被封装的）B的区域。在C++中，没有跨越区域的重载——对于这条规则，继承类也不例外。更多的细节，参见《C++语言的设计和演变》和《C++程序设计语言》。</P>
<P></P>
<P>但是，如果我需要在基类和继承类之间建立一组重载的f()函数呢？很简单，使用using声明：</P>
<P></P>
<P>class D : public B {</P>
<P>public:</P>
<P>using B::f; // make every f from B available</P>
<P>double f(double d) { cout &lt;&lt; "f(double): "; return d+1.3; }</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>进行这个修改之后，输出结果将是：</P>
<P></P>
<P>f(int): 3</P>
<P>f(double): 3.6</P>
<P></P>
<P>这样，在B的f()和D的f()之间，重载确实实现了，并且选择了一个最合适的f()进行调用。</P>
<P></P>
<P>我能够在构造函数中调用一个虚拟函数吗？</P>
<P></P>
<P>可以，但是要小心。它可能不象你期望的那样工作。在构造函数中，虚拟调用机制不起作用，因为继承类的重载还没有发生。对象先从基类被创建，“基类先于继承类(base before derived)”。</P>
<P></P>
<P>看看这个：</P>
<P></P>
<P>#include&lt;string&gt;</P>
<P>#include&lt;iostream&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>class B {</P>
<P>public:</P>
<P>B(const string&amp; ss) { cout &lt;&lt; "B constructor\n"; f(ss); }</P>
<P>virtual void f(const string&amp;) { cout &lt;&lt; "B::f\n";}</P>
<P>};</P>
<P></P>
<P>class D : public B {</P>
<P>public:</P>
<P>D(const string &amp; ss) :B(ss) { cout &lt;&lt; "D constructor\n";}</P>
<P>void f(const string&amp; ss) { cout &lt;&lt; "D::f\n"; s = ss; }</P>
<P>private:</P>
<P>string s;</P>
<P>};</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>D d("Hello");</P>
<P>}</P>
<P></P>
<P>程序编译以后会输出：</P>
<P></P>
<P>B constructor</P>
<P>B::f</P>
<P>D constructor</P>
<P></P>
<P>注意不是D::f。设想一下，如果出于不同的规则，B::B()可以调用D::f()的话，会产生什么样的后果：因为构造函数D::D()还没有运行，D::f()将会试图将一个还没有初始化的字符串s赋予它的参数。结果很可能是导致立即崩溃。</P>
<P></P>
<P>析构函数在“继承类先于基类”的机制下运行，因此虚拟机制的行为和构造函数一样：只有本地定义(local definitions)被使用——不会调用虚拟函数，以免触及对象中的（现在已经被销毁的）继承类的部分。</P>
<P></P>
<P>更多的细节，参见《C++语言的设计和演变》13.2.4.2和《C++程序设计语言》15.4.3。</P>
<P></P>
<P>有人暗示，这只是一条实现时的人为制造的规则。不是这样的。事实上，要实现这种不安全的方法倒是非常容易的：在构造函数中直接调用虚拟函数，就象调用其它函数一样。但是，这样就意味着，任何虚拟函数都无法编写了，因为它们需要依靠基类的固定的创建(invariants established by base classes)。这将会导致一片混乱。</P>
<P></P>
<P>有没有“指定位置删除”(placement delete)？</P>
<P></P>
<P>没有，不过如果你需要的话，可以自己写一个。</P>
<P></P>
<P>看看这个指定位置创建(placement new)，它将对象放进了一系列Arena中；</P>
<P></P>
<P>class Arena {</P>
<P>public:</P>
<P>void* allocate(size_t);</P>
<P>void deallocate(void*);</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>void* operator new(size_t sz, Arena&amp; a)</P>
<P>{</P>
<P>return a.allocate(sz);</P>
<P>}</P>
<P></P>
<P>Arena a1(some arguments);</P>
<P>Arena a2(some arguments);</P>
<P></P>
<P>这样实现了之后，我们就可以这么写：</P>
<P></P>
<P>X* p1 = new(a1) X;</P>
<P>Y* p2 = new(a1) Y;</P>
<P>Z* p3 = new(a2) Z;</P>
<P>// ...</P>
<P></P>
<P>但是，以后怎样正确地销毁这些对象呢？没有对应于这种“placement new”的内建的“placement delete”，原因是，没有一种通用的方法可以保证它被正确地使用。在C++的类型系统中，没有什么东西可以让我们确认，p1一定指向一个由Arena类型的a1分派的对象。p1可能指向任何东西分派的任何一块地方。</P>
<P></P>
<P>然而，有时候程序员是知道的，所以这是一种方法：</P>
<P></P>
<P>template&lt;class T&gt; void destroy(T* p, Arena&amp; a)</P>
<P>{</P>
<P>if (p) {</P>
<P>p-&gt;~T(); // explicit destructor call</P>
<P>a.deallocate(p);</P>
<P>}</P>
<P>}</P>
<P></P>
<P>现在我们可以这么写：</P>
<P></P>
<P>destroy(p1,a1);</P>
<P>destroy(p2,a2);</P>
<P>destroy(p3,a3);</P>
<P></P>
<P>如果Arena维护了它保存着的对象的线索，你甚至可以自己写一个析构函数，以避免它发生错误。</P>
<P></P>
<P>这也是可能的：定义一对相互匹配的操作符new()和delete()，以维护《C++程序设计语言》15.6中的类继承体系。参见《C++语言的设计和演变》10.4和《C++程序设计语言》19.4.5。</P>
<P></P>
<P>我能防止别人继承我自己的类吗？</P>
<P></P>
<P>可以，但你为什么要那么做呢？这是两个常见的回答：</P>
<P></P>
<P>效率：避免我的函数被虚拟调用</P>
<P>安全：保证我的类不被用作一个基类（例如，保证我能够复制对象而不用担心出事）</P>
<P></P>
<P>根据我的经验，效率原因往往是不必要的担心。在C++中，虚拟函数调用是如此之快，以致于它们在一个包含虚拟函数的类中被实际使用时，相比普通的函数调用，根本不会产生值得考虑的运行期开支。注意，仅仅通过指针或引用时，才会使用虚拟调用机制。当直接通过对象名字调用一个函数时，虚拟函数调用的开支可以被很容易地优化掉。</P>
<P></P>
<P>如果确实有真正的需要，要将一个类封闭起来以防止虚拟调用，那么可能首先应该问问为什么它们是虚拟的。我看见过一些例子，那些性能表现不佳的函数被设置为虚拟，没有其他原因，仅仅是因为“我们习惯这么干”。</P>
<P></P>
<P>这个问题的另一个部分，由于逻辑上的原因如何防止类被继承，有一个解决方案。不幸的是，这个方案并不完美。它建立在这样一个事实的基础之上，那就是：大多数的继承类必须建立一个虚拟的基类。这是一个例子：</P>
<P></P>
<P>class Usable;</P>
<P></P>
<P>class Usable_lock {</P>
<P>friend class Usable;</P>
<P>private:</P>
<P>Usable_lock() {}</P>
<P>Usable_lock(const Usable_lock&amp;) {}</P>
<P>};</P>
<P></P>
<P>class Usable : public virtual Usable_lock {</P>
<P>// ...</P>
<P>public:</P>
<P>Usable();</P>
<P>Usable(char*);</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>Usable a;</P>
<P></P>
<P>class DD : public Usable { };</P>
<P></P>
<P>DD dd; // 错误: DD::DD() 不能访问</P>
<P>// Usable_lock::Usable_lock()是一个私有成员</P>
<P></P>
<P>(来自《C++语言的设计和演变》11.4.3)</P>
<P></P>
<P>为什么不能为模板参数定义约束（constraints）？</P>
<P></P>
<P>可以的，而且方法非常简单和通用。</P>
<P></P>
<P>看看这个：</P>
<P></P>
<P>template&lt;class Container&gt;</P>
<P>void draw_all(Container&amp; c)</P>
<P>{</P>
<P>for_each(c.begin(),c.end(),mem_fun(&amp;Shape::draw));</P>
<P>}</P>
<P></P>
<P>如果出现类型错误，可能是发生在相当复杂的for_each()调用时。例如，如果容器的元素类型是int，我们将得到一个和for_each()相关的含义模糊的错误(因为不能够对对一个int值调用Shape::draw的方法)。</P>
<P></P>
<P>为了提前捕捉这个错误，我这样写：</P>
<P></P>
<P>template&lt;class Container&gt;</P>
<P>void draw_all(Container&amp; c)</P>
<P>{</P>
<P>Shape* p = c.front(); // accept only containers of Shape*s</P>
<P></P>
<P>for_each(c.begin(),c.end(),mem_fun(&amp;Shape::draw));</P>
<P>}</P>
<P></P>
<P>对于现在的大多数编译器，中间变量p的初始化将会触发一个易于了解的错误。这个窍门在很多语言中都是通用的，而且在所有的标准创建中都必须这样做。在成品的代码中，我也许可以这样写：</P>
<P></P>
<P>template&lt;class Container&gt;</P>
<P>void draw_all(Container&amp; c)</P>
<P>{</P>
<P>typedef typename Container::value_type T;</P>
<P>Can_copy&lt;T,Shape*&gt;(); // accept containers of only Shape*s</P>
<P></P>
<P>for_each(c.begin(),c.end(),mem_fun(&amp;Shape::draw));</P>
<P>}</P>
<P></P>
<P>这样就很清楚了，我在建立一个断言(assertion)。Can_copy模板可以这样定义：</P>
<P></P>
<P>template&lt;class T1, class T2&gt; struct Can_copy {</P>
<P>static void constraints(T1 a, T2 b) { T2 c = a; b = a; }</P>
<P>Can_copy() { void(*p)(T1,T2) = constraints; }</P>
<P>};</P>
<P></P>
<P>Can_copy(在运行时)检查T1是否可以被赋值给T2。Can_copy&lt;T,Shape*&gt;检查T是否是Shape*类型，或者是一个指向由Shape类公共继承而来的类的对象的指针，或者是被用户转换到Shape*类型的某个类型。注意这个定义被精简到了最小：</P>
<P></P>
<P>一行命名要检查的约束，和要检查的类型</P>
<P>一行列出指定的要检查的约束(constraints()函数)</P>
<P>一行提供触发检查的方法(通过构造函数)</P>
<P></P>
<P>注意这个定义有相当合理的性质：</P>
<P></P>
<P>你可以表达一个约束，而不用声明或复制变量，因此约束的编写者可以用不着去设想变量如何被初始化，对象是否能够被复制，被销毁，以及诸如此类的事情。(当然，约束要检查这些属性的情况时例外。)</P>
<P>使用现在的编译器，不需要为约束产生代码</P>
<P>定义和使用约束，不需要使用宏</P>
<P>当约束失败时，编译器会给出可接受的错误信息，包括“constraints”这个词（给用户一个线索），约束的名字，以及导致约束失败的详细错误（例如“无法用double*初始化Shape*”）。</P>
<P></P>
<P>那么，在C++语言中，有没有类似于Can_copy——或者更好——的东西呢？在《C++语言的设计和演变》中，对于在C++中实现这种通用约束的困难进行了分析。从那以来，出现了很多方法，来让约束类变得更加容易编写，同时仍然能触发良好的错误信息。例如，我信任我在Can_copy中使用的函数指针的方式，它源自Alex Stepanov和Jeremy Siek。我并不认为Can_copy()已经可以标准化了——它需要更多的使用。同样，在C++社区中，各种不同的约束方式被使用；到底是哪一种约束模板在广泛的使用中被证明是最有效的，还没有达成一致的意见。</P>
<P></P>
<P>但是，这种方式非常普遍，比语言提供的专门用于约束检查的机制更加普遍。无论如何，当我们编写一个模板时，我们拥有了C++提供的最丰富的表达力量。看看这个：</P>
<P></P>
<P>template&lt;class T, class B&gt; struct Derived_from {</P>
<P>static void constraints(T* p) { B* pb = p; }</P>
<P>Derived_from() { void(*p)(T*) = constraints; }</P>
<P>};</P>
<P></P>
<P>template&lt;class T1, class T2&gt; struct Can_copy {</P>
<P>static void constraints(T1 a, T2 b) { T2 c = a; b = a; }</P>
<P>Can_copy() { void(*p)(T1,T2) = constraints; }</P>
<P>};</P>
<P></P>
<P>template&lt;class T1, class T2 = T1&gt; struct Can_compare {</P>
<P>static void constraints(T1 a, T2 b) { a==b; a!=b; a&lt;b; }</P>
<P>Can_compare() { void(*p)(T1,T2) = constraints; }</P>
<P>};</P>
<P></P>
<P>template&lt;class T1, class T2, class T3 = T1&gt; struct Can_multiply {</P>
<P>static void constraints(T1 a, T2 b, T3 c) { c = a*b; }</P>
<P>Can_multiply() { void(*p)(T1,T2,T3) = constraints; }</P>
<P>};</P>
<P></P>
<P>struct B { };</P>
<P>struct D : B { };</P>
<P>struct DD : D { };</P>
<P>struct X { };</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>Derived_from&lt;D,B&gt;();</P>
<P>Derived_from&lt;DD,B&gt;();</P>
<P>Derived_from&lt;X,B&gt;();</P>
<P>Derived_from&lt;int,B&gt;();</P>
<P>Derived_from&lt;X,int&gt;();</P>
<P></P>
<P>Can_compare&lt;int,float&gt;();</P>
<P>Can_compare&lt;X,B&gt;();</P>
<P>Can_multiply&lt;int,float&gt;();</P>
<P>Can_multiply&lt;int,float,double&gt;();</P>
<P>Can_multiply&lt;B,X&gt;();</P>
<P></P>
<P>Can_copy&lt;D*,B*&gt;();</P>
<P>Can_copy&lt;D,B*&gt;();</P>
<P>Can_copy&lt;int,B*&gt;();</P>
<P>}</P>
<P></P>
<P>// 典型的“元素必须继承自Mybase*”约束:</P>
<P></P>
<P>template&lt;class T&gt; class Container : Derived_from&lt;T,Mybase&gt; {</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>事实上，Derived_from并不检查来源（derivation），而仅仅检查转换（conversion），不过这往往是一个更好的约束。为约束想一个好名字是很难的。</P>
<P></P>
<P>既然已经有了优秀的qsort()函数，为什么还需要一个sort()？</P>
<P></P>
<P>对于初学者来说，</P>
<P></P>
<P>qsort(array,asize,sizeof(elem),elem_compare);</P>
<P></P>
<P>看上去太古怪了，而且比这个更难理解：</P>
<P></P>
<P>sort(vec.begin(),vec.end());</P>
<P></P>
<P>对于专家来说，在元素与比较方式（comparison criteria）都相同的情况下，sort()比qsort()更快，这是很重要的。而且，qsort()是通用的，所以它可以用于不同容器类型、元素类型、比较方式的任意有意义的组合。举例来说：</P>
<P></P>
<P>struct Record {</P>
<P>string name;</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>struct name_compare { // 使用"name"作为键比较Record</P>
<P>bool operator()(const Record&amp; a, const Record&amp; b) const</P>
<P>{ return a.name&lt;b.name; }</P>
<P>};</P>
<P></P>
<P>void f(vector&lt;Record&gt;&amp; vs)</P>
<P>{</P>
<P>sort(vs.begin(), vs.end(), name_compare());</P>
<P>// ...</P>
<P>} </P>
<P></P>
<P>而且，很多人欣赏sort()是因为它是类型安全的，使用它不需要进行造型（cast），没有人必须去为基本类型写一个compare()函数。</P>
<P></P>
<P>更多的细节，参见我的文章《将标准C++作为一种新的语言来学习》（Learning C++ as a New language），可以从我的文章列表中找到。</P>
<P></P>
<P>sort()胜过qsort()的主要原因是，比较操作在内联（inlines）上做得更好。</P>
<P></P>
<P>什么是函数对象（function object）？</P>
<P></P>
<P>顾名思义，就是在某种方式上表现得象一个函数的对象。典型地，它是指一个类的实例，这个类定义了应用操作符operator()。</P>
<P></P>
<P>函数对象是比函数更加通用的概念，因为函数对象可以定义跨越多次调用的可持久的部分（类似静态局部变量），同时又能够从对象的外面进行初始化和检查（和静态局部变量不同）。例如：</P>
<P></P>
<P>class Sum {</P>
<P>int val;</P>
<P>public:</P>
<P>Sum(int i) :val(i) { }</P>
<P>operator int() const { return val; } // 取得值</P>
<P></P>
<P>int operator()(int i) { return val+=i; } // 应用</P>
<P>};</P>
<P></P>
<P>void f(vector v)</P>
<P>{</P>
<P>Sum s = 0; // initial value 0</P>
<P>s = for_each(v.begin(), v.end(), s); // 求所有元素的和</P>
<P>cout &lt;&lt; "the sum is " &lt;&lt; s &lt;&lt; "\n";</P>
<P></P>
<P>//或者甚至：</P>
<P>cout &lt;&lt; "the sum is " &lt;&lt; for_each(v.begin(), v.end(), Sum(0)) &lt;&lt; "\n";</P>
<P>}</P>
<P></P>
<P>注意一个拥有应用操作符的函数对象可以被完美地内联化（inline），因为它没有涉及到任何指针，后者可能导致拒绝优化。与之形成对比的是，现有的优化器几乎不能（或者完全不能？）将一个通过函数指针的调用内联化。</P>
<P></P>
<P>在标准库中，函数对象被广泛地使用以获得弹性。</P>
<P></P>
<P>我应该如何对付内存泄漏？</P>
<P></P>
<P>写出那些不会导致任何内存泄漏的代码。很明显，当你的代码中到处充满了new 操作、delete操作和指针运算的话，你将会在某个地方搞晕了头，导致内存泄漏，指针引用错误，以及诸如此类的问题。这和你如何小心地对待内存分配工作其实完全没有关系：代码的复杂性最终总是会超过你能够付出的时间和努力。于是随后产生了一些成功的技巧，它们依赖于将内存分配（allocations）与重新分配（deallocation）工作隐藏在易于管理的类型之后。标准容器（standard containers）是一个优秀的例子。它们不是通过你而是自己为元素管理内存，从而避免了产生糟糕的结果。想象一下，没有string和vector的帮助，写出这个：</P>
<P></P>
<P>#include&lt;vector&gt;</P>
<P>#include&lt;string&gt;</P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;algorithm&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>int main() // small program messing around with strings</P>
<P>{</P>
<P>cout &lt;&lt; "enter some whitespace-separated words:\n";</P>
<P>vector&lt;string&gt; v;</P>
<P>string s;</P>
<P>while (cin&gt;&gt;s) v.push_back(s);</P>
<P></P>
<P>sort(v.begin(),v.end());</P>
<P></P>
<P>string cat;</P>
<P>typedef vector&lt;string&gt;::const_iterator Iter;</P>
<P>for (Iter p = v.begin(); p!=v.end(); ++p) cat += *p+"+";</P>
<P>cout &lt;&lt; cat &lt;&lt; '\n';</P>
<P>}</P>
<P></P>
<P>你有多少机会在第一次就得到正确的结果？你又怎么知道你没有导致内存泄漏呢？</P>
<P></P>
<P>注意，没有出现显式的内存管理，宏，造型，溢出检查，显式的长度限制，以及指针。通过使用函数对象和标准算法（standard algorithm），我可以避免使用指针——例如使用迭代子（iterator），不过对于一个这么小的程序来说有点小题大作了。</P>
<P></P>
<P>这些技巧并不完美，要系统化地使用它们也并不总是那么容易。但是，应用它们产生了惊人的差异，而且通过减少显式的内存分配与重新分配的次数，你甚至可以使余下的例子更加容易被跟踪。早在1981年，我就指出，通过将我必须显式地跟踪的对象的数量从几万个减少到几打，为了使程序正确运行而付出的努力从可怕的苦工，变成了应付一些可管理的对象，甚至更加简单了。</P>
<P></P>
<P>如果你的程序还没有包含将显式内存管理减少到最小限度的库，那么要让你程序完成和正确运行的话，最快的途径也许就是先建立一个这样的库。</P>
<P></P>
<P>模板和标准库实现了容器、资源句柄以及诸如此类的东西，更早的使用甚至在多年以前。异常的使用使之更加完善。</P>
<P></P>
<P>如果你实在不能将内存分配/重新分配的操作隐藏到你需要的对象中时，你可以使用资源句柄（resource handle），以将内存泄漏的可能性降至最低。这里有个例子：我需要通过一个函数，在空闲内存中建立一个对象并返回它。这时候可能忘记释放这个对象。毕竟，我们不能说，仅仅关注当这个指针要被释放的时候，谁将负责去做。使用资源句柄，这里用了标准库中的auto_ptr，使需要为之负责的地方变得明确了。</P>
<P></P>
<P>#include&lt;memory&gt;</P>
<P>#include&lt;iostream&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>struct S {</P>
<P>S() { cout &lt;&lt; "make an S\n"; }</P>
<P>~S() { cout &lt;&lt; "destroy an S\n"; }</P>
<P>S(const S&amp;) { cout &lt;&lt; "copy initialize an S\n"; }</P>
<P>S&amp; operator=(const S&amp;) { cout &lt;&lt; "copy assign an S\n"; }</P>
<P>};</P>
<P></P>
<P>S* f()</P>
<P>{</P>
<P>return new S; // 谁该负责释放这个S？</P>
<P>};</P>
<P></P>
<P>auto_ptr&lt;S&gt; g()</P>
<P>{</P>
<P>return auto_ptr&lt;S&gt;(new S); // 显式传递负责释放这个S</P>
<P>}</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>cout &lt;&lt; "start main\n";</P>
<P>S* p = f();</P>
<P>cout &lt;&lt; "after f() before g()\n";</P>
<P>// S* q = g(); // 将被编译器捕捉</P>
<P>auto_ptr&lt;S&gt; q = g();</P>
<P>cout &lt;&lt; "exit main\n";</P>
<P>// *p产生了内存泄漏</P>
<P>// *q被自动释放</P>
<P>}</P>
<P></P>
<P>在更一般的意义上考虑资源，而不仅仅是内存。</P>
<P></P>
<P>如果在你的环境中不能系统地应用这些技巧（例如，你必须使用别的地方的代码，或者你的程序的另一部分简直是原始人类（译注：原文是Neanderthals，尼安德特人，旧石器时代广泛分布在欧洲的猿人）写的，如此等等），那么注意使用一个内存泄漏检测器作为开发过程的一部分，或者插入一个垃圾收集器（garbage collector）。</P>
<P></P>
<P>我为什么在捕获一个异常之后就不能继续？</P>
<P></P>
<P>换句话说，C++为什么不提供一种简单的方式，让程序能够回到异常抛出点之后，并继续执行？</P>
<P></P>
<P>主要的原因是，如果从异常处理之后继续，那么无法预知掷出点之后的代码如何对待异常处理，是否仅仅继续执行，就象什么也没有发生一样。异常处理者无法知道，在继续之前，有关的上下文环境（context）是否是“正确”的。要让这样的代码正确执行，抛出异常的编写者与捕获异常的编写者必须对彼此的代码与上下文环境都非常熟悉才行。这样会产生非常复杂的依赖性，因此无论在什么情况下，都会导致一系列严重的维护问题。</P>
<P></P>
<P>当我设计C++的异常处理机制时，我曾经认真地考虑过允许这种继续的可能性，而且在标准化的过程中，这个问题被非常详细地讨论过。请参见《C++语言的设计和演变》中的异常处理章节。</P>
<P></P>
<P>在一次新闻组的讨论中，我曾经以一种稍微不同的方式回答过这个问题。</P>
<P></P>
<P>为什么C++中没有相当于realloc()的函数？</P>
<P></P>
<P>如果你需要，你当然可以使用realloc()。但是，realloc()仅仅保证能工作于这样的数组之上：它们被malloc()（或者类似的函数）分配，包含一些没有用户定义的复制构造函数（copy constructors）的对象。而且，要记住，与通常的期望相反，realloc()有时也必须复制它的参数数组。</P>
<P></P>
<P>在C++中，处理内存重新分配的更好的方法是，使用标准库中的容器，例如vector，并让它自我增长。</P>
<P></P>
<P>如何使用异常？</P>
<P></P>
<P>参见《C++程序设计语言》第4章，第8.3节，以及附录E。这个附录针对的是如何在要求苛刻的程序中写出异常安全的代码的技巧，而不是针对初学者的。一个关键的技术是“资源获得即初始化”（resource acquisiton is initialization），它使用一些有析构函数的类，来实现强制的资源管理。</P>
<P></P>
<P>怎样从输入中读取一个字符串？</P>
<P></P>
<P>你可以用这种方式读取一个单独的以空格结束的词：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;string&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>cout &lt;&lt; "Please enter a word:\n";</P>
<P></P>
<P>string s;</P>
<P>cin&gt;&gt;s;</P>
<P></P>
<P>cout &lt;&lt; "You entered " &lt;&lt; s &lt;&lt; '\n';</P>
<P>}</P>
<P></P>
<P>注意，这里没有显式的内存管理，也没有可能导致溢出的固定大小的缓冲区。</P>
<P></P>
<P>如果你确实想得到一行而不是一个单独的词，可以这样做：</P>
<P></P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;string&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>cout &lt;&lt; "Please enter a line:\n";</P>
<P></P>
<P>string s;</P>
<P>getline(cin,s);</P>
<P></P>
<P>cout &lt;&lt; "You entered " &lt;&lt; s &lt;&lt; '\n';</P>
<P>}</P>
<P></P>
<P>在《C++程序设计语言》（可在线获得）的第3章，可以找到一个对诸如字符串与流这样的标准库工具的简介。对于使用C与C++进行简单输入输出的详细比较，参见我的文章《将标准C++作为一种新的语言来学习》(Learning Standard C++ as a New Language)，你可以在本人著作列表(my publications list)中下载到它。</P>
<P></P>
<P>为什么C++不提供“finally”的构造？</P>
<P></P>
<P>因为C++提供了另外一种方法，它几乎总是更好的：“资源获得即初始化”（resource acquisiton is initialization）技术。基本的思路是，通过一个局部对象来表现资源，于是局部对象的析构函数将会释放资源。这样，程序员就不会忘记释放资源了。举例来说：</P>
<P></P>
<P>class File_handle {</P>
<P>FILE* p;</P>
<P>public:</P>
<P>File_handle(const char* n, const char* a)</P>
<P>{ p = fopen(n,a); if (p==0) throw Open_error(errno); }</P>
<P>File_handle(FILE* pp)</P>
<P>{ p = pp; if (p==0) throw Open_error(errno); }</P>
<P></P>
<P>~File_handle() { fclose(p); }</P>
<P></P>
<P>operator FILE*() { return p; }</P>
<P></P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>void f(const char* fn)</P>
<P>{</P>
<P>File_handle f(fn,"rw"); //打开fn进行读写</P>
<P>// 通过f使用文件</P>
<P>}</P>
<P></P>
<P>在一个系统中，需要为每一个资源都使用一个“资源句柄”类。无论如何，我们不需要为每一个资源获得都写出“finally”语句。在实时系统中，资源获得要远远多于资源的种类，因此和使用“finally”构造相比，“资源获得即初始化”技术会产生少得多的代码。</P>
<P></P>
<P>什么是自动指针（auto_ptr），为什么没有自动数组（auto_array）？</P>
<P></P>
<P>auto_ptr是一个非常简单的句柄类的例子，在&lt;memory&gt;中定义，通过“资源获得即初始化”技术支持异常安全。auto_ptr保存着一个指针，能够象指针一样被使用，并在生存期结束时释放指向的对象。举例：</P>
<P></P>
<P>#include&lt;memory&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>struct X {</P>
<P>int m;</P>
<P>// ..</P>
<P>};</P>
<P></P>
<P>void f()</P>
<P>{</P>
<P>auto_ptr&lt;X&gt; p(new X);</P>
<P>X* q = new X;</P>
<P></P>
<P>p-&gt;m++; // 象一个指针一样使用p</P>
<P>q-&gt;m++;</P>
<P>// ...</P>
<P></P>
<P>delete q;</P>
<P>}</P>
<P></P>
<P>如果在...部分抛出了一个异常，p持有的对象将被auto_ptr的析构函数正确地释放，而q指向的X对象则产生了内存泄漏。更多的细节，参见《C++程序设计语言》14.4.2节。</P>
<P></P>
<P>auto_ptr是一个非常简单的类。特别地，它不是一个引用计数（reference counted）的指针。如果你将一个auto_ptr赋值给另一个，那么被赋值的auto_ptr将持有指针，而原来的auto_ptr将持有0。举例：</P>
<P></P>
<P>#include&lt;memory&gt;</P>
<P>#include&lt;iostream&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>struct X {</P>
<P>int m;</P>
<P>// ..</P>
<P>};</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>auto_ptr&lt;X&gt; p(new X);</P>
<P>auto_ptr&lt;X&gt; q(p);</P>
<P>cout &lt;&lt; "p " &lt;&lt; p.get() &lt;&lt; " q " &lt;&lt; q.get() &lt;&lt; "\n";</P>
<P>}</P>
<P></P>
<P>将会打印出一个指向0的指针和一个指向非0的指针。例如：</P>
<P></P>
<P>p 0x0 q 0x378d0</P>
<P></P>
<P>auto_ptr::get()返回那个辅助的指针。</P>
<P></P>
<P>这种“转移”语义不同于通常的“复制”语义，这是令人惊讶的。特别地，永远不要使用auto_ptr作为一个标准容器的成员。标准容器需要通常的“复制”语义。例如：</P>
<P></P>
<P>std::vector&lt;auto_ptr&lt;X&gt; &gt;v; // 错误</P>
<P></P>
<P>auto_ptr只持有指向一个单独元素的指针，而不是指向一个数组的指针：</P>
<P></P>
<P>void f(int n)</P>
<P>{</P>
<P>auto_ptr&lt;X&gt; p(new X[n]); //错误</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>这是错误的，因为析构函数会调用delete而不是delete[]来释放指针，这样就不会调用余下的n-1个X的析构函数。</P>
<P></P>
<P>那么我们需要一个auto_array来持有数组吗？不。没有auto_array。原因是根本没有这种需要。更好的解决方案是使用vector：</P>
<P></P>
<P>void f(int n)</P>
<P>{</P>
<P>vector&lt;X&gt; v(n);</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>当...部分发生异常时，v的析构函数会被正确地调用。</P>
<P></P>
<P>可以混合使用C风格与C++风格的内存分派与重新分配吗？</P>
<P></P>
<P>在这种意义上是可以的：你可以在同一个程序中使用malloc()和new。</P>
<P></P>
<P>在这种意义上是不行的：你不能使用malloc()来建立一个对象，又通过delete来释放它。你也不能用new建立一个新的对象，然后通过free()来释放它，或者通过realloc()在数组中再建立一个新的。</P>
<P></P>
<P>C++中的new和delete操作可以保证正确的构造和析构：构造函数和析构函数在需要它们的时候被调用。C风格的函数alloc(), calloc(), free(), 和realloc()却不能保证这一点。此外，用new和delete来获得和释放的原始内存，并不一定能保证与malloc()和free()兼容。如果这种混合的风格在你的系统中能够运用，只能说是你走运——暂时的。</P>
<P></P>
<P>如果你觉得需要使用realloc()——或者要做更多——考虑使用标准库中的vector。例如：</P>
<P></P>
<P>// 从输入中将词读取到一个字符串vector中</P>
<P></P>
<P>vector&lt;string&gt; words;</P>
<P>string s;</P>
<P>while (cin&gt;&gt;s &amp;&amp; s!=".") words.push_back(s);</P>
<P></P>
<P>vector会视需要自动增长。</P>
<P></P>
<P>更多的例子与讨论，参见我的文章《将标准C++作为一种新的语言来学习》(Learning Standard C++ as a New Language)，你可以在本人著作列表(my publications list)中下载到它。</P>
<P></P>
<P>我为什么必须使用一个造型来转换*void？</P>
<P></P>
<P>在C语言中，你可以隐式地将*void转换为*T。这是不安全的。考虑一下：</P>
<P></P>
<P>#include&lt;stdio.h&gt;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>char i = 0;</P>
<P>char j = 0;</P>
<P>char* p = &amp;i;</P>
<P>void* q = p;</P>
<P>int* pp = q; /* 不安全的，在C中可以，C++不行 */</P>
<P></P>
<P>printf("%d %d\n",i,j);</P>
<P>*pp = -1; /* 覆盖了从i开始的内存 */</P>
<P>printf("%d %d\n",i,j);</P>
<P>}</P>
<P></P>
<P>使用一个并不指向T类型的T*将是一场灾难。因此，在C++中，如果从一个void*得到一个T*，你必须进行显式转换。举例来说，要得到上列程序的这个令人别扭的效果，你可以这样写：</P>
<P></P>
<P>int* pp = (int*)q;</P>
<P></P>
<P>或者使用一个新的类型造型，以使这种没有检查的类型转换操作变得更加清晰：</P>
<P></P>
<P>int* pp = static_cast&lt;int*&gt;(q);</P>
<P></P>
<P>造型被最好地避免了。</P>
<P></P>
<P>在C语言中，这种不安全的转换最常见的应用之一，是将malloc()的结果赋予一个合适的指针。例如：</P>
<P></P>
<P>int* p = malloc(sizeof(int));</P>
<P></P>
<P>在C++中，使用类型安全的new操作符：</P>
<P></P>
<P>int* p = new int;</P>
<P></P>
<P>附带地，new操作符还提供了胜过malloc()的新特性：</P>
<P></P>
<P>new不会偶然分配错误的内存数量；</P>
<P>new会隐式地检查内存耗尽情况，而且</P>
<P>new提供了初始化。</P>
<P></P>
<P>举例：</P>
<P></P>
<P>typedef std::complex&lt;double&gt; cmplx;</P>
<P></P>
<P>/* C风格: */</P>
<P>cmplx* p = (cmplx*)malloc(sizeof(int)); /* 错误：类型不正确 */</P>
<P>/* 忘记测试p==0 */</P>
<P>if (*p == 7) { /* ... */ } /* 糟糕，忘记了初始化*p */</P>
<P></P>
<P>// C++风格:</P>
<P>cmplx* q = new cmplx(1,2); // 如果内存耗尽，将抛出一个bad_alloc异常</P>
<P>if (*q == 7) { /* ... */ }</P>
<P></P>
<P>我如何定义一个类内部（in-class）的常量？</P>
<P></P>
<P>如果你需要一个通过常量表达式来定义的常量，例如数组的范围，你有两种选择：</P>
<P></P>
<P>class X {</P>
<P>static const int c1 = 7;</P>
<P>enum { c2 = 19 };</P>
<P></P>
<P>char v1[c1];</P>
<P>char v2[c2];</P>
<P></P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>乍看起来，c1的声明要更加清晰，但是要注意的是，使用这种类内部的初始化语法的时候，常量必须是被一个常量表达式初始化的整型或枚举类型，而且必须是static和const形式。这是很严重的限制：</P>
<P></P>
<P>class Y {</P>
<P>const int c3 = 7; // 错误：不是static</P>
<P>static int c4 = 7; // 错误：不是const</P>
<P>static const float c5 = 7; // 错误：不是整型</P>
<P>};</P>
<P></P>
<P>我倾向使用枚举的方式，因为它更加方便，而且不会诱使我去使用不规范的类内初始化语法。</P>
<P></P>
<P>那么，为什么会存在这种不方便的限制呢？一般来说，类在一个头文件中被声明，而头文件被包含到许多互相调用的单元去。但是，为了避免复杂的编译器规则，C++要求每一个对象只有一个单独的定义。如果C++允许在类内部定义一个和对象一样占据内存的实体的话，这种规则就被破坏了。对于C++在这个设计上的权衡，请参见《C++语言的设计和演变》。</P>
<P></P>
<P>如果你不需要用常量表达式来初始化它，那么可以获得更大的弹性：</P>
<P></P>
<P>class Z {</P>
<P>static char* p; // 在定义中初始化</P>
<P>const int i; // 在构造函数中初始化</P>
<P>public:</P>
<P>Z(int ii) :i(ii) { }</P>
<P>};</P>
<P></P>
<P>char* Z::p = "hello, there";</P>
<P></P>
<P>你可以获取一个static成员的地址，当且仅当它有一个类外部的定义的时候：</P>
<P></P>
<P>class AE {</P>
<P>// ...</P>
<P>public:</P>
<P>static const int c6 = 7;</P>
<P>static const int c7 = 31;</P>
<P>};</P>
<P></P>
<P>const int AE::c7; // 定义</P>
<P></P>
<P>int f()</P>
<P>{</P>
<P>const int* p1 = &amp;AE::c6; // 错误：c6没有左值</P>
<P>const int* p2 = &amp;AE::c7; // ok</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>为什么delete不会将操作数置0？</P>
<P></P>
<P>考虑一下：</P>
<P></P>
<P>delete p;</P>
<P>// ...</P>
<P>delete p;</P>
<P></P>
<P>如果在...部分没有涉及到p的话，那么第二个“delete p;”将是一个严重的错误，因为C++的实现（译注：原文为a C++ implementation，当指VC++这样的实现了C++标准的具体工具）不能有效地防止这一点（除非通过非正式的预防手段）。既然delete 0从定义上来说是无害的，那么一个简单的解决方案就是，不管在什么地方执行了“delete p;”，随后都执行“p=0;”。但是，C++并不能保证这一点。</P>
<P></P>
<P>一个原因是，delete的操作数并不需要一个左值（lvalue）。考虑一下：</P>
<P></P>
<P>delete p+1;</P>
<P>delete f(x);</P>
<P></P>
<P>在这里，被执行的delete并没有拥有一个可以被赋予0的指针。这些例子可能很少见，但它们的确指出了，为什么保证“任何指向被删除对象的指针都为0”是不可能的。绕过这条“规则”的一个简单的方法是，有两个指针指向同一个对象：</P>
<P></P>
<P>T* p = new T;</P>
<P>T* q = p;</P>
<P>delete p;</P>
<P>delete q; // 糟糕！</P>
<P></P>
<P>C++显式地允许delete操作将操作数左值置0，而且我曾经希望C++的实现能够做到这一点，但这种思想看来并没有在C++的实现中变得流行。</P>
<P></P>
<P>如果你认为指针置0很重要，考虑使用一个销毁的函数：</P>
<P></P>
<P>template&lt;class T&gt; inline void destroy(T*&amp; p) { delete p; p = 0; }</P>
<P></P>
<P>考虑一下，这也是为什么需要依靠标准库的容器、句柄等等，来将对new和delete的显式调用降到最低限度的另一个原因。</P>
<P></P>
<P>注意，通过引用来传递指针（以允许指针被置0）有一个额外的好处，能防止destroy()在右值上（rvalue）被调用：</P>
<P></P>
<P>int* f();</P>
<P>int* p;</P>
<P>// ...</P>
<P>destroy(f()); // 错误：应该使用一个非常量（non-const）的引用传递右值</P>
<P>destroy(p+1); // 错误：应该使用一个非常量（non-const）的引用传递右值</P>
<P></P>
<P>我能够写“void main()”吗？</P>
<P></P>
<P>这种定义：</P>
<P></P>
<P>void main() { /* ... */ }</P>
<P></P>
<P>在C++中从未被允许，在C语言中也是一样。参见ISO C++标准3.6.1[2]或者ISO C标准5.1.2.2.1。规范的实现接受这种方式：</P>
<P></P>
<P>int main() { /* ... */ }</P>
<P></P>
<P>和</P>
<P></P>
<P>int main(int argc, char* argv[]) { /* ... */ }</P>
<P></P>
<P>一个规范的实现可能提供许多版本的main()，但它们都必须返回int类型。main()返回的int值，是程序返回一个值给调用它的系统的方式。在那些不具备这种方式的系统中，返回值被忽略了，但这并不使“void main()”在C++或C中成为合法的。即使你的编译器接受了“void main()”，也要避免使用它，否则你将冒着被C和C++程序员视为无知的风险。</P>
<P></P>
<P>在C++中，main()并不需要包含显式的return语句。在这种情况下，返回值是0，表示执行成功。例如：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>std::cout &lt;&lt; "This program returns the integer value 0\n";</P>
<P>}</P>
<P></P>
<P>注意，无论是ISO C++还是C99，都不允许在声明中漏掉类型。那就是说，与C89和ARM C++形成对照，当声明中缺少类型时，并不会保证是“int”。于是：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P></P>
<P>main() { /* ... */ }</P>
<P></P>
<P>是错误的，因为缺少main()的返回类型。</P>
<P></P>
<P>为什么我不能重载点符号，::，sizeof，等等？</P>
<P></P>
<P>大多数的运算符能够被程序员重载。例外的是：</P>
<P></P>
<P>. (点符号) :: ?: sizeof</P>
<P></P>
<P>并没有什么根本的原因要禁止重载?:。仅仅是因为，我没有发现有哪种特殊的情况需要重载一个三元运算符。注意一个重载了 表达式1？表达式2：表达式3 的函数，不能够保证表达式2：表达式3中只有一个会被执行。</P>
<P></P>
<P>Sizeof不能够被重载是因为内建的操作（built-in operations），诸如对一个指向数组的指针进行增量操作，必须依靠它。考虑一下：</P>
<P></P>
<P>X a[10];</P>
<P>X* p = &amp;a[3];</P>
<P>X* q = &amp;a[3];</P>
<P>p++; // p指向a[4]</P>
<P>// 那么p的整型值必须比q的整型值大出一个sizeof(X)</P>
<P></P>
<P>所以，sizeof(X)不能由程序员来赋予一个不同的新意义，以免违反基本的语法。</P>
<P></P>
<P>在N::m中，无论N还是m都不是值的表达式；N和m是编译器知道的名字，::执行一个（编译期的）范围解析，而不是表达式求值。你可以想象一下，允许重载x::y的话，x可能是一个对象而不是一个名字空间（namespace）或者一个类，这样就会导致——与原来的表现相反——产生新的语法（允许 表达式1::表达式2）。很明显，这种复杂性不会带来任何好处。</P>
<P></P>
<P>理论上来说，.（点运算符）可以通过使用和-&gt;一样的技术来进行重载。但是，这样做会导致一个问题，那就是无法确定操作的是重载了.的对象呢，还是通过.引用的一个对象。例如：</P>
<P></P>
<P></P>
<P>class Y {</P>
<P>public:</P>
<P>void f();</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>class X { // 假设你能重载.</P>
<P>Y* p;</P>
<P>Y&amp; operator.() { return *p; }</P>
<P>void f();</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>void g(X&amp; x)</P>
<P>{</P>
<P>x.f(); // X::f还是Y::f还是错误？</P>
<P>}</P>
<P></P>
<P>这个问题能够用几种不同的方法解决。在标准化的时候，哪种方法最好还没有定论。更多的细节，请参见《C++语言的设计和演变》。</P>
<P></P>
<P>怎样将一个整型值转换为一个字符串？</P>
<P></P>
<P>最简单的方法是使用一个字符串流（stringstream）：</P>
<P></P>
<P>#include&lt;iostream&gt;</P>
<P>#include&lt;string&gt;</P>
<P>#include&lt;sstream&gt;</P>
<P>using namespace std;</P>
<P></P>
<P>string itos(int i) // 将int转换成string</P>
<P>{</P>
<P>stringstream s;</P>
<P>s &lt;&lt; i;</P>
<P>return s.str();</P>
<P>}</P>
<P></P>
<P>int main()</P>
<P>{</P>
<P>int i = 127;</P>
<P>string ss = itos(i);</P>
<P>const char* p = ss.c_str();</P>
<P></P>
<P>cout &lt;&lt; ss &lt;&lt; " " &lt;&lt; p &lt;&lt; "\n";</P>
<P>}</P>
<P></P>
<P>自然地，这种技术能够将任何使用&lt;&lt;输出的类型转换为字符串。对于字符串流的更多说明，参见《C++程序设计语言》21.5.3节。</P>
<P></P>
<P>“int* p”正确还是“int *p”正确？</P>
<P></P>
<P>二者都是正确的，因为二者在C和C++中都是有效的，而且意义完全一样。就语言的定义与相关的编译器来说，我们还可以说“int*p”或者“int * p”。</P>
<P></P>
<P>在“int* p”和“int *p”之间的选择与正确或错误无关，而只关乎风格与侧重点。C侧重表达式；对声明往往比可能带来的问题考虑得更多。另一方面，C++则非常重视类型。</P>
<P></P>
<P>一个“典型的C程序员”写成“int *p”，并且解释说“*p表示一个什么样的int”以强调语法，而且可能指出C（与C++）的语法来证明这种风格的正确性。是的，在语法上*被绑定到名字p上。</P>
<P></P>
<P>一个“典型的C++程序员”写成“int* p”，并且解释说“p是一个指向int的指针类型”以强调类型。是的，p是一个指向int的指针类型。我明确地倾向于这种侧重方向，而且认为对于学好更多的高级C++这是很重要的。</P>
<P></P>
<P>严重的混乱（仅仅）发生在当人们试图在一条声明中声明几个指针的时候：</P>
<P></P>
<P>int* p, p1; // 也许是错的：p1不是一个int*</P>
<P></P>
<P>把*放到名字这一边，看来也不能有效地减少这种错误：</P>
<P></P>
<P>int *p, p1; // 也许是错的？</P>
<P></P>
<P>为每一个名字写一条声明最大程度地解决了问题——特别是当我们初始化变量的时候。人们几乎不会这样写：</P>
<P></P>
<P>int* p = &amp;i;</P>
<P>int p1 = p; // 错误：int用一个int*初始化了</P>
<P></P>
<P>如果他们真的这么干了，编译器也会指出。</P>
<P></P>
<P>每当事情可以有两种方法完成，有人就会迷惑。每当事情仅仅是一个风格的问题，争论就会没完没了。为每一个指针写一条声明，而且永远都要初始化变量，这样，混乱之源就消失了。更多的关于C的声明语法的讨论，参见《C++语言的设计和演变》。</P>
<P></P>
<P>对于我的代码，哪一种布局风格（layout style）是最好的？</P>
<P></P>
<P>这种风格问题属于个人的爱好。人们往往对布局风格的问题持有强烈的意见，不过，也许一贯性比某种特定的风格更加重要。象大多数人一样，我花了很长的时间，来为我的偏好作出一个固定的结论。</P>
<P></P>
<P>我个人使用通常称为“K&amp;R”的风格。当使用C语言没有的构造函数时，需要增加新的习惯，这样就变成了一种有时被称为“Stroustrup”的风格。例如：</P>
<P></P>
<P>class C : public B {</P>
<P>public:</P>
<P>// ...</P>
<P>};</P>
<P></P>
<P>void f(int* p, int max)</P>
<P>{</P>
<P>if (p) {</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>for (int i = 0; i&lt;max; ++i) {</P>
<P>// ...</P>
<P>}</P>
<P>}</P>
<P></P>
<P>比大多数布局风格更好，这种风格保留了垂直的空格，我喜欢尽可能地在合理的情况下对齐屏幕。对函数开头的大括弧的放置，有助于我第一眼就分别出类的定义和函数的定义。</P>
<P></P>
<P>缩进是非常重要的。</P>
<P></P>
<P>设计问题，诸如作为主要接口的抽象基类的使用，使用模板以表现有弹性的类型安全的抽象，以及正确地使用异常以表现错误，比布局风格的选择要重要得多。</P>
<P></P>
<P>我应该将“const”放在类型之前还是之后？</P>
<P></P>
<P>我把它放在前面，但那仅仅是个人爱好问题。“const T”和“T const”总是都被允许的，而且是等效的。例如：</P>
<P></P>
<P>const int a = 1; // ok</P>
<P>int const b = 2; // also ok</P>
<P></P>
<P>我猜想第一种版本可能会让少数（更加固守语法规范）的程序员感到迷惑。</P>
<P></P>
<P>为什么？当我发明“const”（最初的名称叫做“readonly”，并且有一个对应的“writeonly”）的时候，我就允许它出现在类型之前或之后，因为这样做不会带来任何不明确。标准之前的C和C++规定了很少的（如果有的话）特定的顺序规范。</P>
<P></P>
<P>我不记得当时有过任何有关顺序问题的深入思考或讨论。那时，早期的一些使用者——特别是我——仅仅喜欢这种样子：</P>
<P></P>
<P>const int c = 10;</P>
<P></P>
<P>看起来比这种更好：</P>
<P></P>
<P>int const c = 10;</P>
<P></P>
<P>也许我也受了这种影响：在我最早的一些使用“readonly”的例子中</P>
<P></P>
<P>readonly int c = 10;</P>
<P></P>
<P>比这个更具有可读性：</P>
<P></P>
<P>int readonly c = 10;</P>
<P></P>
<P>我创造的那些最早的使用“const”的（C或C++）代码，看来已经在全球范围内取代了“readonly”。</P>
<P></P>
<P>我记得这个语法的选择在几个人——例如Dennis Ritchie——当中讨论过，但我不记得当时我倾向于哪种语言了。</P>
<P></P>
<P>注意在固定指针（const pointer）中，“const”永远出现在“*”之后。例如：</P>
<P></P>
<P>int *const p1 = q; // 指向int变量的固定指针</P>
<P>int const* p2 = q; //指向int常量的指针</P>
<P>const int* p3 = q; //指向int常量的指针</P>
<P></P>
<P>使用宏有什么问题？</P>
<P></P>
<P>宏不遵循C++中关于范围和类型的规则。这经常导致一些微妙的或不那么微妙的问题。因此，C++提供更适合其他的C++（译注：原文为the rest of C++，当指C++除了兼容C以外的部分）的替代品，例如内联函数、模板与名字空间。</P>
<P></P>
<P>考虑一下：</P>
<P></P>
<P>#include "someheader.h"</P>
<P></P>
<P>struct S {</P>
<P>int alpha;</P>
<P>int beta;</P>
<P>};</P>
<P></P>
<P>如果某人（不明智地）地写了一个叫“alpha”或“beta”的宏，那么它将不会被编译，或者被错误地编译，产生不可预知的结果。例如，“someheader.h”可能包含：</P>
<P></P>
<P>#define alpha 'a'</P>
<P>#define beta b[2]</P>
<P></P>
<P>将宏（而且仅仅是宏）全部大写的习惯，会有所帮助，但是对于宏并没有语言层次上的保护机制。例如，虽然成员的名字包含在结构体的内部，但这无济于事：在编译器能够正确地辨别这一点之前，宏已经将程序作为一个字符流进行了处理。顺便说一句，这是C和C++程序开发环境和工具能够被简化的一个主要原因：人与编译器看到的是不同的东西。</P>
<P></P>
<P>不幸的是，你不能假设别的程序员总是能够避免这种你认为“相当白痴”的事情。例如，最近有人报告我，他们遇到了一个包含goto的宏。我也见过这种情况，而且听到过一些——在很脆弱的时候——看起来确实有理的意见。例如：</P>
<P></P>
<P>#define prefix get_ready(); int ret__</P>
<P>#define Return(i) ret__=i; do_something(); goto exit</P>
<P>#define suffix exit: cleanup(); return ret__</P>
<P></P>
<P>void f()</P>
<P>{</P>
<P>prefix;</P>
<P>// ...</P>
<P>Return(10);</P>
<P>// ...</P>
<P>Return(x++);</P>
<P>//...</P>
<P>suffix;</P>
<P>}</P>
<P></P>
<P>作为一个维护的程序员，就会产生这种印象；将宏“隐藏”到一个头文件中——这并不罕见——使得这种“魔法”更难以被辨别。</P>
<P></P>
<P>一个常见的微妙问题是，一个函数风格的宏并不遵守函数参数传递的规则。例如：</P>
<P></P>
<P>#define square(x) (x*x)</P>
<P></P>
<P>void f(double d, int i)</P>
<P>{</P>
<P>square(d); // 好</P>
<P>square(i++); // 糟糕：这表示 (i++*i++)</P>
<P>square(d+1); //糟糕：这表示(d+1*d+1); 也就是 (d+d+1)</P>
<P>// ...</P>
<P>}</P>
<P></P>
<P>“d+1”的问题，可以通过在“调用”时或宏定义时添加一对圆括号来解决：</P>
<P></P>
<P>#define square(x) ((x)*(x)) /*这样更好 */</P>
<P></P>
<P>但是， i++被执行了两次（可能并不是有意要这么做）的问题仍然存在。</P>
<P></P>
<P>是的，我确实知道有些特殊的宏并不会导致C/C++预处理宏这样的问题。但是，我无心去发展C++中的宏。作为替代，我推荐使用C++语言中合适的工具，例如内联函数，模板，构造函数（用来初始化），析构函数（用来清除），异常（用来退出上下文环境），等等。<BR></P>
<P align=left><BR></P><img src ="http://www.blogjava.net/bcims/aggbug/28340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 19:53 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个非常好的C++文档网站！！</title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28339.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 11:51:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28339.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28339.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28339.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28339.html</trackback:ping><description><![CDATA[<CENTER>
<TABLE cellSpacing=0 cellPadding=0 width=688 bgColor=#ffffff>
<TBODY>
<TR>
<TD vAlign=bottom align=middle height=35></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width=688 bgColor=#4d99e5>
<TBODY>
<TR>
<TD>
<TABLE cellSpacing=1 cellPadding=1 width="100%" border=0>
<TBODY>
<TR bgColor=#4d99e5>
<TD align=left height=21>
<TABLE height=18 cellSpacing=1 cellPadding=1 width="100%" border=0>
<TBODY>
<TR>
<TD><FONT color=#ffffff>&nbsp;</FONT><A class=a0 title=http://www.MHDN.net href="http://www.trainlinux.com/"><FONT color=#ffffff>首页</FONT></A><FONT color=#ffffff> &gt; 编程开发 &gt; C/C++</FONT> </TD>
<TD class=f01 align=right><FONT face=arial><B><FONT color=#ffffff>1 | </FONT><A class=a0 href="http://www.trainlinux.com/program/9/2.html"><FONT color=#ffffff>2</FONT></A><FONT color=#ffffff> | </FONT><A class=a0 href="http://www.trainlinux.com/program/9/3.html"><FONT color=#ffffff>3</FONT></A><FONT color=#ffffff> | </FONT><A class=a0 href="http://www.trainlinux.com/program/9/4.html"><FONT color=#ffffff>4</FONT></A><FONT color=#ffffff> | </FONT><A class=a0 href="http://www.trainlinux.com/program/9/5.html"><FONT color=#ffffff>5</FONT></A></B></FONT>&nbsp; </TD></TR></TBODY></TABLE></TD></TR>
<TR bgColor=#ffffff>
<TD vAlign=top align=middle height=200>
<TABLE cellSpacing=1 cellPadding=1 width="95%">
<TBODY>
<TR>
<TD height=5></TD></TR>
<TR>
<TD class=f14 vAlign=top height=200><SPAN class=dot><FONT color=#4d99e5 size=1>●</FONT></SPAN> <A href="http://www.trainlinux.com/p/2003-01-05/6422.html" target=_blank>用 GDB 调试程序</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2003-01-05 21:33)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-20/6370.html" target=_blank>深度探索C++对象模型</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-20 20:26)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6342.html" target=_blank>深度探索C++对象模型（9）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:13)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6341.html" target=_blank>深度探索C++对象模型（8）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:12)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6340.html" target=_blank>深度探索C++对象模型（7）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:12)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6339.html" target=_blank>深度探索C++对象模型（6）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:11)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6338.html" target=_blank>深度探索C++对象模型（5）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:10)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-19/6337.html" target=_blank>深度探索C++对象模型（4）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-19 13:09)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6336.html" target=_blank>深度探索C++对象模型（3）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 13:08)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6335.html" target=_blank>深度探索C++对象模型（2）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 13:06)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6334.html" target=_blank>深度探索C++对象模型（1）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 13:05)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6331.html" target=_blank>如何用加密API获得纯文本的会话密钥</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 12:47)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6330.html" target=_blank>一种简单注册码加密的例子分析</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 12:45)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-18/6329.html" target=_blank>IBM的MARS加密算法实现(下)</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-18 12:43)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6328.html" target=_blank>IBM的MARS加密算法实现(上)</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 12:42)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6327.html" target=_blank>关于MFC和STL的使用</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 12:40)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6326.html" target=_blank>C++编程杂谈之三：面向对象（续）</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 12:05)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6325.html" target=_blank>C++编程杂谈之二：面向对象</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 12:03)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6324.html" target=_blank>C++编程杂谈之一：编译器</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 12:01)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6323.html" target=_blank>为什么operator=操作符返回引用</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 11:58)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6322.html" target=_blank>自制性能测试类</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 11:57)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-17/6321.html" target=_blank>定义函数对象</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-17 11:56)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6320.html" target=_blank>声明函数指针并实现回调</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-16 11:56)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6319.html" target=_blank>在名字空间中声明类和成员函数</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-16 11:55)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6317.html" target=_blank>如何用编程获取CD-ROM的驱动器盘符</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-16 11:49)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6316.html" target=_blank>C++指针使用方法解惑</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-16 11:46)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6315.html" target=_blank>如何在派生类中的隐藏基类的虚拟重载函数</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-16 11:46)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6314.html" target=_blank>为什么要在operator=中返回"*this"的引用</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-16 11:45)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-16/6313.html" target=_blank>const使用详解</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-11-16 11:44)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-15/6312.html" target=_blank>关于内联汇编的几个技巧</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-15 11:42)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-15/6311.html" target=_blank>捕获数学函数异常</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-15 11:40)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-15/6310.html" target=_blank>命名空间的概念</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-15 11:39)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-11-15/6309.html" target=_blank>内联汇编基础知识</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.vckbase.com 2002-11-15 11:38)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-01-25/4388.html" target=_blank>C语言中操作字符串的一些函数源代码</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(http://www.fanqiang.com 2002-01-25 14:36)</SPAN><BR><SPAN class=dot>●</SPAN></FONT></FONT> <A href="http://www.trainlinux.com/p/2002-01-25/4387.html" target=_blank>一个执行中的程式如何知道自己的 pathname?</A> <FONT size=1><FONT color=#4d99e5><SPAN class=date>(2002-01-25 14:31)</SPAN><BR><IMG height=8 src="http://www.trainlinux.com/image/c.gif"><BR></FONT></FONT></TD></TR>
<TR>
<TD align=middle height=38><FONT color=#0070b0>【 更多<B> 1 <A class=a02 href="http://www.trainlinux.com/program/9/2.html">2</A> <A class=a02 href="http://www.trainlinux.com/program/9/3.html">3</A> <A class=a02 href="http://www.trainlinux.com/program/9/4.html">4</A> <A class=a02 href="http://www.trainlinux.com/program/9/5.html">5</A></B>&nbsp;】</FONT></TD></TR></TBODY></TABLE></TD></TR>
<TR bgColor=#4d99e5>
<TD align=left height=21>
<TABLE height=18 cellSpacing=1 cellPadding=1 width="100%" border=0>
<TBODY>
<TR>
<TD></TD>
<TD align=right><A href="http://www.trainlinux.com/"><FONT face=arial><B>Home</B></FONT></A>&nbsp; </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width=688 border=0>
<TBODY>
<TR>
<TD align=middle height=31><FONT color=#4d99e5></FONT></TD></TR></TBODY></TABLE></CENTER><img src ="http://www.blogjava.net/bcims/aggbug/28339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 19:51 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习c++好站  &lt;1&gt;</title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28338.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 11:50:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28338.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28338.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28338.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28338.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28338.html</trackback:ping><description><![CDATA[<BR>
<DIV class=top>&nbsp;&nbsp;&nbsp;<A href="http://www.orkut.com/Community.aspx?cmm=6210702" target=_blank><IMG title="Huihoo Orkut 社区，欢迎所有关心、支持huihoo的朋友加入本社区。" src="http://www.huihoo.com/huihoo.png" border=0></A>&nbsp;&nbsp;&nbsp;<B><FONT face=times color=#0039b6 size=6>H</FONT><FONT face=times color=#30a72f size=6>u</FONT><FONT face=times color=#c41200 size=6>i</FONT><FONT face=times color=#0039b6 size=6>h</FONT><FONT face=times color=#c41200 size=6>o</FONT><FONT face=times color=#f3c518 size=6>o</FONT></B>&nbsp;&nbsp; <FONT face=times color=#c41200 size=6>for</FONT>&nbsp;&nbsp;&nbsp;<FONT face=times color=#30a72f size=6>Your</FONT>&nbsp;&nbsp;&nbsp;<FONT face=times color=#c41200 size=6>Study</FONT><FONT face=times color=#0039b6 size=6>&nbsp;+&nbsp;</FONT><FONT face=times color=#30a72f size=6>Work</FONT><FONT face=times color=#c41200 size=6>&nbsp;+&nbsp;</FONT><FONT face=times color=#0039b6 size=6>Life</FONT>&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#f3c518 size=6>:)</FONT> </DIV>
<DIV class=tabs><A class=selected href="http://www.huihoo.com/about/index.html">Huihoo</A> <A class=plain href="http://www.huihoo.org/" target=_blank>Projects</A> <A class=plain href="http://www.huihoo.com/gnu_linux/index.html">Linux</A> <A class=plain href="http://www.huihoo.com/gnu/index.html">GNU,C,C++</A> <A class=plain href="http://www.huihoo.com/java/index.html">JAVA</A> <A class=plain href="http://www.huihoo.com/xml/index.html">SOA &amp; Web Services</A> <A class=plain href="http://www.huihoo.com/corba/index.html">CORBA</A> <A class=plain href="http://www.spreaddebian.com/ref/5" target=_blank><FONT color=red>Spread Debian</FONT></A> </DIV>
<DIV class=personalBar>今天你分享了吗？ </DIV>
<TABLE class=columns>
<TBODY>
<TR>
<TD class=left>
<DIV class=box>
<H5>&nbsp;灰狐论坛&nbsp;</H5>
<DIV class=body>
<DIV class="content odd"><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=77">求职招聘</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=76">开源社区,业界动态</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=166"><FONT color=red>Firefox,Web2,P2P</FONT></A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=103">VoIP,Asterisk</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=97"><FONT color=red>Streaming,IPTV</FONT></A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=7">SOA,ESB,BPM</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=125"><FONT color=red>ACE/TAO</FONT>,CORBA</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=186">C,C++,GCC,GNU</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=183">Java Web开发,框架</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=5">JDK,SDK,GlassFish</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=99">JOnAS,Geronimo</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=73"><FONT color=red>Berkeley</FONT>,PgSQL</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=72"><FONT color=red>Debian,LAMP</FONT></A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=112">FreeBSD,OpenBSD</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=167"><FONT color=red>OpenSolaris</FONT></A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=173">Xen,Server,Storage</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.huihoo.com/forum/forumdisplay.php?fid=169">原来生活可以更美的:)</A><BR></DIV></DIV></DIV>
<DIV class=box>
<H5>&nbsp;Google朋友圈&nbsp;</H5>
<DIV class=body>
<DIV class="content odd"><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=6210702" target=_blank><FONT color=red>Huihoo朋友圈</FONT></A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=5528551" target=_blank>Google</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=6108231" target=_blank>Mozilla,Firefox</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=5732321" target=_blank>eMule,eDonkey</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=6136544" target=_blank>Middleware</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=6133898" target=_blank>Database</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=6084552" target=_blank>Storage,Server</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=5534249" target=_blank>Debian,Ubuntu</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=5924087" target=_blank>OpenSolaris</A><BR><IMG src="http://www.huihoo.com/i/forum.gif"> <A href="http://www.orkut.com/Community.aspx?cmm=5925948" target=_blank>FreeBSD,OpenBSD</A><BR>发送邮件给我以获得邀请<BR><IMG src="http://www.huihoo.com/about/i/ihuihoo-gmail.png"> </DIV></DIV></DIV>
<DIV class=box>
<H5>&nbsp;灰狐团队&nbsp;</H5>
<DIV class=body>
<DIV class="content odd"><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.com/about/index.html">Huihoo成员</A><BR><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.com/about/join_us.html">加入Huihoo</A><BR><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.com/forum/viewthread.php?tid=3080">招募论坛版主</A><BR><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.org/about/developer.html" target=_blank>招募开发人员</A><BR><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.com/about/forum.html">Huihoo讨论会,活动</A><BR><IMG src="http://www.huihoo.com/about/huihoo-small.png"> <A href="http://www.huihoo.com/art/index.html">Huihoo设计与艺术</A><BR></DIV></DIV></DIV>
<DIV align=center><A href="http://www.alexa.com/data/details/traffic_details?q=&amp;url=huihoo.com" target=_blank>Alexa排名</A> </DIV><BR><SELECT onchange="javascript:if (this.options[this.selectedIndex].value!='#') { window.open(this.options[this.selectedIndex].value)}" name=url> <OPTION value=# selected>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;合作组织&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</OPTION> <OPTION value=http://www.linuxplus.cn/>Linuxplus</OPTION> <OPTION value=http://www.chinaarchitect.net/>中国软件架构师网</OPTION> <OPTION value=http://cosoft.org.cn/>共创软件联盟</OPTION> <OPTION value=http://www.bstek.com/>extra web构件开发平台</OPTION> <OPTION value=http://www.mdasky.com/>主导国内MDA潮流</OPTION> <OPTION value=http://www.primeton.com/>普元--Internet构件技术</OPTION> <OPTION value=http://www.cbdonline.com.cn/>中构在线</OPTION> <OPTION value=http://www.tongtech.com/>东方通科技</OPTION> <OPTION value=http://dev2dev.bea.com.cn/>BEA dev2dev</OPTION> <OPTION value=http://www.fawcette.com/china/>发赛特</OPTION> <OPTION value=http://developer.ccidnet.com/>赛迪网开发者</OPTION> <OPTION value=http://www.pconline.com.cn/pcedu/>太平洋电脑网网络学院</OPTION> <OPTION value=http://www.ciscoedu.com/>思科\CCNA\CCNP\CCIE</OPTION> <OPTION value=http://www.nytraining.com.cn/>交大南洋IT培训中心</OPTION> <OPTION value=http://www.sxsoft.com>软件项目交易网</OPTION> <OPTION value=http://www.infofj.com>信息福建IT站</OPTION> <OPTION value=http://www.javaresearch.org/>Java研究组织</OPTION> <OPTION value=http://www.cnjsp.com/>中国JSP技术网站</OPTION> <OPTION value=http://www.huangdong.com>MAven中国</OPTION> <OPTION value=http://www.umlchina.com/>UMLChina</OPTION> <OPTION value=http://www.sawin.cn/>系统分析之窗</OPTION> <OPTION value=http://www.uml.net.cn/>UML软件工程组织</OPTION> <OPTION value=http://www.cnjavaclub.com/>中国JAVA俱乐部</OPTION> <OPTION value=http://cwqu.3322.org/>goddess goer orient</OPTION> <OPTION value=http://www.cnjm.net/>中国JAVA手机网</OPTION> <OPTION value=http://www.javajia.com/>JAVA家</OPTION> <OPTION value=http://www.code-labs.com/>代码实验室</OPTION> <OPTION value=http://www.freelamp.com>FreeLamp.com</OPTION> <OPTION value=http://www.cngnu.org/>炎黄角马</OPTION> <OPTION value=http://www.trainlinux.com>诚恩Linux培训工作室</OPTION> <OPTION value=http://www.hhcn.org/>华恒嵌入式linux资料站点</OPTION> <OPTION value=http://www.csai.cn>中国系统分析员</OPTION> <OPTION value=http://www.sobooks.com/>SoBooks(计算机图书)</OPTION> <OPTION value=http://www.frontfree.net>北京工业大学放飞技术网</OPTION> <OPTION value=http://www.matrix.org.cn>Matrix开源技术</OPTION> <OPTION value=http://www.studyjava.com/link/fyindex.asp?user=huihu>学习JAVA</OPTION> <OPTION value=http://www.softcon.cn/>2003 中国软件技术大会</OPTION> <OPTION value=http://www.examlink.com/>中国认证网址大全</OPTION> <OPTION value=http://www.testage.net/>测试时代</OPTION> <OPTION value=http://www.moon-soft.com/>月光源程序下载</OPTION> <OPTION value=http://www.youngzsoft.com/cn/>代理服务器软件</OPTION></SELECT> </TD>
<TD class=main>
<H4>与Google一起分享互联网, 现在就加入<A href="http://groups.google.com/group/huihoo" target=_blank>Google用户组(已有<FONT color=red size=4>470</FONT>多名会员)</A></H4>
<UL>
<LI>Google Services: <A href="http://www.google.com/alerts" target=_blank>Alerts</A>,<A href="http://answers.google.com/" target=_blank>Answers</A>,<A href="http://www.livejournal.com/users/googleblog/" target=_blank>Googleblog</A>,<A href="http://blogsearch.google.com/" target=_blank>Blog Search</A>,<A href="http://www.blogger.com/" target=_blank>Blogger</A>,<A href="http://code.google.com/" target=_blank>Code</A>,<BR><A href="http://catalogs.google.com/" target=_blank>Catalogs</A>,<A href="http://www.google.com/dirhp" target=_blank>Directory</A>,<A href="http://froogle.google.com/" target=_blank> Froogle</A>,<A href="http://gmail.google.com/" target=_blank>Gmail</A>,<A href="http://groups.google.com/group/huihoo" target=_blank><FONT color=red>Groups</FONT></A>,<A href="http://images.google.com/" target=_blank>Images</A>,<A href="http://labs.google.com/" target=_blank>Labs</A>,<A href="http://local.google.com/" target=_blank>Local </A>,<A href="http://maps.google.com/" target=_blank>Maps</A>,<BR><A href="http://mobile.google.com/" target=_blank>Mobile</A>,<A href="http://news.google.com/" target=_blank>News</A>,<A href="http://print.google.com/" target=_blank>Print</A>,<A href="http://scholar.google.com/" target=_blank>Scholar</A>,<A href="http://sms.google.com/" target=_blank>SMS</A>,<A href="http://local.google.com/options/specialsearches.html" target=_blank>Special Searches</A>,<A href="http://local.google.com/options/universities.html" target=_blank>University Search</A>,<BR><A href="http://www.google.com/webhp" target=_blank>Web Search</A>,<A href="http://local.google.com/help/features.html" target=_blank>Web Search Features</A><A href="http://www.google.com/ig" target=_blank>Personalize Your Homepage</A>,<BR><A href="http://www.google.com/appliance/" target=_blank>Appliance</A>, <A href="http://www.google.com/services/" target=_blank>Business Solutions</A>, <A href="http://www.googlestore.com/" target=_blank>Store</A>, <A href="http://toolbar.google.com/dc/" target=_blank>Compute</A>,<A href="http://services.google.com/tc/Welcome.html" target=_blank>In Your Language</A>, <BR><A href="http://www.google.com/press/zeitgeist.html" target=_blank>Zeitgeist</A>,<A href="http://reader.google.com/" target=_blank>Google Reader</A>,<A href="http://www.orkut.com/Community.aspx?cmm=5528551" target=_blank><FONT color=red>Orkut</FONT></A>,<A href="http://video.google.com/" target=_blank>Google Video</A>,<A href="http://moon.google.com/" target=_blank>Google Moon</A><BR><A href="http://toolbar.google.com/firefox/extensions/index.html" target=_blank>Google Extensions for Firefox</A>,<A href="http://www.google.com/psearch" target=_blank>Personalized Search</A>,<A href="http://webaccelerator.google.com/" target=_blank>Google Web Accelerator</A>. 
<LI>Google Tools：<A href="http://desktop.google.com/?promo=mp-gds-v1-1" target=_blank>Desktop</A>,<A href="http://earth.google.com/" target=_blank>Earth</A>,<A href="http://www.picasa.com/index.php?tid=Y2NpZD0zNzQ4" target=_blank>Picasa</A>,<A href="http://www.hello.com/" target=_blank>Hello</A>,<A href="http://www.google.com/talk" target=_blank>Talk</A>,<A href="http://toolbar.google.com/?promo=mor-tb-en" target=_blank>Toolbar</A>,<A href="http://www.google.com/language_tools" target=_blank>Translate</A>. 
<LI>Google Ad：<A href="https://adwords.google.com/" target=_blank>Adwords</A>,<A href="https://www.google.com/adsense/" target=_blank>AdSense</A>,<A href="http://www.urchin.com/lang/zh-CN/" target=_blank>Urchin Web分析</A>. 
<LI>Special Searches : <A href="http://www.google.com/linux" target=_blank>Linux</A>, <A href="http://www.google.com/mac" target=_blank>Mac</A>, <A href="http://www.google.com/bsd" target=_blank>BSD</A>, <A href="http://www.google.com/microsoft" target=_blank>Microsoft</A>, <A href="http://www.google.com/unclesam" target=_blank>US</A>, <A href="http://www.google.com/firefox?client=firefox-a&amp;rls=org.mozilla:zh-CN:official" target=_blank>Firefox</A>,<A href="http://www.google.com/mac.html" target=_blank>Macintosh</A>. 
<LI>Other : <A href="http://bbs.keyhole.com/" target=_blank>Google Earth Community</A>,<A href="http://google.blognewschannel.com/" target=_blank>InsideGoogle</A>,<A href="http://zh.wikipedia.org/wiki/Google" target=_blank>Google Wikipedia</A> </LI></UL>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.huihoo.com/internet/google/google_adwords.gif">, <IMG src="http://www.huihoo.com/internet/google/google_sm.gif"> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://groups.google.com/group/huihoo" target=_blank>让我们一起交流和分享Google AdWords, Google AdSense成功的广告模式</A> <BR>
<BLOCKQUOTE>
<P>
<TABLE cellSpacing=0 cellPadding=0 width="50%" border=0>
<TBODY>
<TR>
<TD align=middle colSpan=2 height=24><!-- SiteSearch Google -->
<FORM action=http://www.google.com/custom method=get target=_top>
<TABLE bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD vAlign=top noWrap align=left height=32><A href="http://www.google.com/"><IMG alt=Google src="http://www.huihoo.com/i/google.gif" border=0></IMG></A> </TD>
<TD noWrap><INPUT type=hidden value=www.huihoo.com name=domains></INPUT> <INPUT maxLength=255 size=33 name=q></INPUT> <INPUT type=submit value=搜索 name=sa></INPUT> </TD></TR>
<TR>
<TD>&nbsp;</TD>
<TD noWrap>
<TABLE>
<TBODY>
<TR>
<TD><INPUT type=radio CHECKED value="" name=sitesearch></INPUT> <FONT color=#000000 size=-1>Web</FONT> </TD>
<TD><INPUT type=radio value=www.huihoo.com name=sitesearch></INPUT> <FONT color=#000000 size=-1>www.huihoo.com</FONT> </TD></TR></TBODY></TABLE><INPUT type=hidden value=pub-2175149392010158 name=client></INPUT> <INPUT type=hidden value=1 name=forid></INPUT> <INPUT type=hidden value=GB2312 name=ie></INPUT> <INPUT type=hidden value=GB2312 name=oe></INPUT> <INPUT type=hidden value=GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:1; name=cof></INPUT> <INPUT type=hidden value=zh-CN name=hl></INPUT> </TD></TR></TBODY></TABLE></FORM><!-- SiteSearch Google --></TD></TR></TBODY></TABLE></P></BLOCKQUOTE>
<TABLE width="100%" align=center border=0>
<TBODY>
<TR>
<TD>
<H4>推荐</H4></TD></TR>
<TR>
<TD>。Source: <A href="http://minnie.tuhs.org/UnixTree/" target=_blank>Unix</A>, <A href="http://cvs.opensolaris.org/source/" target=_blank>OpenSolaris</A>, <A href="http://www.linuxhq.com/kernel/file/index.html" target=_blank>Linux Kernel</A>, <A href="http://lxr.mozilla.org/" target=_blank>Mozilla</A> <BR>。Doxygen: <A href="http://www.huihoo.com/doxygen/guliverkli/html/index.html">guliverkli</A>, <A href="http://www.huihoo.com/doxygen/vlc/html/index.html">vlc</A>, <A href="http://www.huihoo.com/doxygen/shareaza/html/index.html">shareaza</A>, ffdshow, xvid, <A href="http://www.huihoo.com/doxygen/db/html/index.html">Berkeley DB</A>, <A href="http://www.huihoo.com/doxygen/sqlite/html/index.html">Sqlite</A> <BR>。<A href="http://www.huihoo.com/gnu/c-basics/c_tutorial.html">C Tutorial</A>, <A href="http://www.huihoo.com/gnu/c++-tutorial/index.html">C++ Language Tutorial</A>, <A href="http://www.huihoo.com/gnu/vim/vimum.html">Vim User Manual</A>, <A href="http://www.huihoo.com/python/Python-Docs-2.4.2/">Python</A>, PHP, Perl <BR>。<A href="http://www.huihoo.com/npact/content.htm">Computational Science and Web Technology </A><BR>。<A href="http://www.huihoo.com/google/mapreduce/index.html">Google MapReduce: Simplified Data Processing on Large Clusters</A> <BR>。<A href="http://www.huihoo.com/p2p/1/index.html">Peer to Peer (P2P)综述</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=10276">高级文件系统实现者指南(13篇文章,强力推荐)</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=10355">IPTV产业化运营要点问题探析(上,中,下)</A> <BR>。2005年<A href="http://www.debconf.org/" target=_blank>Debian全球大会</A>录像: <A href="http://meetings-archive.debian.net/pub/debian-meetings/2005/debconf5/mpeg/" target=_blank>MPEG格式</A>, <A href="http://meetings-archive.debian.net/pub/debian-meetings/2005/debconf5/dvd/" target=_blank>DVD格式</A>, <A href="http://meetings-archive.debian.net/pub/debian-meetings/2004/debconf4/" target=_blank>2004年大会录像</A> <BR>。<A href="http://www.huihoo.com/debian/survivor-2.0.0/index.html">Debian GNU/Linux Desktop Survival Guide</A> <BR>。<A href="http://www.huihoo.com/debian/learning-debian/index.html">Learning Debian GNU/Linux</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=9424">提问的智慧 [推荐]</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=10108">哪种刀片服务器群集适合您？</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=10097">V4L和DVB核心代码树完成合并</A> <BR>。<A href="http://www.huihoo.com/forum/viewthread.php?tid=10067">JDK 7 征求您的意见</A> <BR>。<A href="http://www.huihoo.com/gnu_linux/redhat/index.html">Red Hat Network 3.6 联机文档</A> <BR>。<A href="http://www.huihoo.com/postgresql/index.html">PostgreSQL最常见问题</A> <BR><BR></TD></TR></TBODY></TABLE>
<TD class=right>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://www.videolan.org/vlc/" target=_blank><IMG title=使用VLC播放你的mp3和电影 src="http://www.huihoo.com/media/getvlc.png" border=0></A> <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://www.huihoo.com/solaris/index.html"><IMG title=OpenSolaris项目 src="http://www.huihoo.com/solaris/opensolaris.gif" border=0><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OpenSolaris,Solaris 操作系统</A> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A href="http://www.orkut.com/Community.aspx?cmm=5534249" target=_blank><IMG title="欢迎加入Debian,Ubuntu朋友圈,一起交流和分享GNU/Linux的惊喜 :)" src="http://www.huihoo.com/debian/i/spreaddebian.gif" border=0></A><BR>已有<FONT color=red size=4>150</FONT>多位Debian GNU/Linux爱好者 <BR><BR>
<DIV class=box width="30%">
<H5>&nbsp;栏目导航&nbsp;</H5>
<DIV class=body>
<DIV class="content odd"><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/open_source/index.html">Open Source</A> | <A href="http://www.huihoo.com/cmdp/index.html">CMDP</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/framework/webwork/index.html">WebWork</A> | <A href="http://www.huihoo.com/framework/struts/index.html">Struts</A> | <A href="http://www.huihoo.com/framework/tapestry/index.html">Tapestry</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/framework/spring/index.html">Spring</A> | <A href="http://www.huihoo.com/framework/hibernate/index.html">Hibernate</A> | <A href="http://www.huihoo.com/framework/myfaces/index.html">JSF</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/jboss/index.html"><FONT color=#30a72f>JBoss</FONT></A> | <A href="http://www.huihoo.com/jonas/index.html">JOnAS</A> | Geronimo <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/document/application.html">J2EE</A>| <A href="http://www.huihoo.com/document/weblogic.html">Weblogic</A>| <A href="http://www.huihoo.com/document/websphere.html">WebSphere</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/ace_tao/index.html">ACE/TAO</A> | <A href="http://www.huihoo.com/ice/2.0.0/manual/index.html">ICE</A> | <A href="http://www.huihoo.com/document/jacorb.html">JacORB</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/document/middleware.html">Middleware</A>| <A href="http://www.huihoo.com/application_infrastructure/index.html">S-Infra</A>| <A href="http://www.huihoo.com/business/index.html">B-Infra</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/postgresql/index.html"><FONT color=#30a72f>PgSql</FONT></A> | <A href="http://www.huihoo.com/mysql/index.html">MySQL</A> | <A href="http://www.huihoo.com/berkeley/index.html">Berkeley</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/eclipse/index.html">Eclipse</A> | <A href="http://www.huihoo.com/netbeans/index.html">NetBeans</A> | <A href="http://www.huihoo.com/gnu/emacs/emacs_user_guide/index.htm">Emacs</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/freebsd/index.html">FreeBSD</A>| <A href="http://www.huihoo.com/openbsd/index.html">OpenBSD</A>| <A href="http://www.huihoo.com/netbsd/cn/netbsd.html">NetBSD</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/solaris/index.html">OpenSolaris</A> | <A href="http://www.huihoo.com/openoffice/index.html">OpenOffice</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/gnu_linux/index.html">Linux</A> | <A href="http://www.huihoo.com/linux/index.html">Linux Application</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/debian/index.html"><FONT color=red>Debian,Ubuntu</FONT></A> | <A href="http://www.huihoo.com/gnu_linux/redhat/index.html">Fedora</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/gentoo/index.html">Gentoo</A>| <A href="http://www.huihoo.com/gnu_linux/lfs/index.html">LFS</A>| <A href="http://www.huihoo.com/rt_embed/uclinux.html">uClinux</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/php/index.html">PHP</A> | <A href="http://www.huihoo.com/python/index.html">Python</A> | Perl <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/compiere/index.html">Compiere</A> | <A href="http://www.huihoo.com/telecom/index.html">Telecom</A> | <A href="http://www.huihoo.com/integration/index.html">EAI</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/rt_embed/index.html">Embed</A> | <A href="http://www.huihoo.com/hardware/index.html">Hardware</A> | <A href="http://www.huihoo.com/ai-robot/index.html">RFID</A> <BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/internet/postfix/pis/book1.html">Postfix</A> | <A href="http://www.huihoo.com/os/index.html">OS</A> | <A href="http://www.huihoo.com/security/OSPKI-html/ospki-book.htm">OS PKI</A> </DIV></DIV></DIV>
<DIV class=box>
<H5>&nbsp;网址导航&nbsp;</H5>
<DIV class=body>
<DIV class="content odd"><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/sites.html">开源项目站点</A><BR><IMG src="http://www.huihoo.com/i1/remote.gif"> <A href="http://www.huihoo.com/resource.html">开放资源站点</A><BR></DIV></DIV></DIV><BR><A href="http://www.isma.tv/" target=_blank><IMG src="http://www.huihoo.com/media/isma.gif" border=0></A> <BR><BR><A href="http://www.chiariglione.org/mpeg/" target=_blank><IMG src="http://www.huihoo.com/media/mpeg.gif" border=0></A> &nbsp; <A href="http://www.linuxtv.org/" target=_blank><IMG src="http://www.huihoo.com/media/linuxtv.jpg" border=0></A> <BR><BR><A href="http://www.grid.org/" target=_blank><IMG src="http://www.huihoo.com/internet/i/join-grid.gif" border=0></A> &nbsp;&nbsp; <A href="http://boinc.berkeley.edu/" target=_blank><IMG src="http://www.huihoo.com/internet/i/boinc.jpg" border=0></A> <BR><BR><A href="http://www.equn.com/" target=_blank><IMG src="http://www.huihoo.com/internet/i/equn.gif" border=0></A> &nbsp;&nbsp; <A href="http://www.chinagrid.net/" target=_blank><IMG src="http://www.huihoo.com/internet/i/chinagrid.jpg" border=0></A> <BR><BR><A href="http://zh.wikipedia.org/wiki/" target=_blank><IMG src="http://www.huihoo.com/internet/i/wikipedia.jpg" border=0></A> &nbsp;&nbsp;&nbsp; <A href="http://www.ourmedia.org/" target=_blank><IMG src="http://www.huihoo.com/internet/i/ourmedia.jpg" border=0></A> <BR><BR><A href="http://www.creativecommons.cn/" target=_blank><IMG src="http://www.huihoo.com/internet/i/creativecommons.gif" border=0></A> &nbsp;&nbsp;&nbsp; <A href="http://www.archive.org/" target=_blank><IMG src="http://www.huihoo.com/internet/i/archive.jpg" border=0></A> <BR><BR></TD></TR></TBODY></TABLE>
<DIV class=footer>© 2005 Huihoo&nbsp;&nbsp;- 整合与服务 </DIV><img src ="http://www.blogjava.net/bcims/aggbug/28338.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 19:50 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28338.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++语言概述</title><link>http://www.blogjava.net/bcims/archive/2006/01/17/28332.html</link><dc:creator>bcims</dc:creator><author>bcims</author><pubDate>Tue, 17 Jan 2006 11:41:00 GMT</pubDate><guid>http://www.blogjava.net/bcims/archive/2006/01/17/28332.html</guid><wfw:comment>http://www.blogjava.net/bcims/comments/28332.html</wfw:comment><comments>http://www.blogjava.net/bcims/archive/2006/01/17/28332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/bcims/comments/commentRss/28332.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/bcims/services/trackbacks/28332.html</trackback:ping><description><![CDATA[C++语言概述

C++语言是一种应用较广的面向对象的程序设计语言，使用它可以实现面向对象的程序设计。面向对象的设计与面向过程的设计是有很大区别的，面向对象的程序设计是在面向过程的程序设计的基础上一个质的飞跃。要学会面向对象的程序设计，首先要学会一种面向对象的语言，即要学会用VC编程，就要先有C++的基础，而学习C++语言首先要认识它面向对象的特性和实现面向对象的方法。

　　C++是一种面向对象的程序设计语言

　　当你首次学习C++时，总会碰到一些在C语言从未见过的概念，如：类、对象、抽象、封装、继承、多态性、虚函数等等。这些概念是C++所具有，下面简单的介绍一下C++对面向对象程序设计方法的支持和实现。

　　1、C++支持数据封装

　　支持数据封装就是支持数据抽象。在C++中，类是支持数据封装的工具，对象则是数据封装的实现。面向过程的程序设计方法与面向对象的程序设计方法在对待数据和函数关系上是不同的，在面向对象的程序设计中，将数据和对该数据进行合法操作的函数封装在一起作为一个类的定义，数据将被隐藏在封装体中，该封装体通过操作接口与外界交换信息。对象被说明具有一个给定类的变量，类类似于C语言中的结构，在C语言中可以定义结构，但这种结构中包含数据，而不包含函数。C++中的类是数据和函数的封装体。在C++中，结构可作为一种特殊的类，它虽然可以包含函数，但是它没有私有或保护的成员。

　　2、C++类中包含私有、公有和保护成员

　　C++类中可定义三种不同访控制权限的成员。一种是私有(Private)成员，只有在类中说明的函数才能访问该类的私有成员，而在该类外的函数不可以访问私有成员；另一种是公有(Public)成员，类外面也可访问公有成员，成为该类的接口；还有一种是保护(Protected)成员，这种成员只有该类的派生类可以访问，其余的在这个类外不能访问。

　　3、C++中通过发关消息来处理对象

　　C++中是通过向对象发关消息来处理对象的，每个对象根据所接收到的消息的性质来决定需要采取的行动，以响应这个消息。响应这些消息是一系列的方法，方法是在类定义中使用函数来定义的，使用一种类似于函数调用的机制把消息发送到一个对象上。

　　4、C++中允许友元破坏封装性

　　类中的私有成员一般是不允许该类外面的任何函数访问的，但是友元便可打破这条禁令，它可以访问该类的私有成员(包含数据成员和成员函数)。友元可以是在类外定义的函数，也可以是在类外定义的整个类，前者称友元函数，后者称为友元类。友元打破了类的封装性，它是C++另一个面向对象的重要牲。

　　5、C++允许函数名和运算符重载

　　C++支持多态性，C++允许一个相同的标识符或运算符代表多个不同实现的函数，这就称标识符或运算符的重载，用户可以根据需要定义标识符重载或运算符重载。

　　6、C++支持继承性

　　C++中可以允许单继承和多继承。一个类可以根据需要生成派生类。派生类继承了基类的所有方法，另外派生类自身还可以定义所需要的不包含在父类中的新方法。一个子类的每个对象包含有从父类那里继承来的数据成员以及自己所特有的数据成员。

　　7、C++支持动态联编

　　C++中可以定义虚函数，通过定义虚函数来支持动态联编。

　　以上是所讲的是C++对面向对象程序设计中的一些主要特征的支持。

　　C++的词法及词法规则

　　1、C++的字符集

　　字符是一些可以区分的最小符号。C++的字符集由大小写英文字母(a-z和A-Z)、数据字符(0-9)、特殊字符(空格，！，#，%，^，&，*，_，<，>，?，\，,)组成。

　　2、单词及词法规则

　　单词又称词法记号，它是由若干个字符组成的具有一定意义的最小词法单元。C++共有6种单词，分别是：标识符、关键字、运算符、分隔符、常量、注释符，在编码时要特别注意这些单词的词法规则。要注意的是C++中的空白符：C++中经常使用空白符，实际上，空白符不是一个字符，它是空格符、换行符和水平制表符的统称。注意，空白符不等于空格符，只是空白符包含空格符。还有一个空字符，要把它与空白符分开。空字符是指ASCII码值为0的那个字符。空字符在C++中有特殊用途，用它来作为字符串的结束符。存放在内存中的字符串常量都在最后有一个结束符，即用空字符，它用转义序列方法表示为’\0’。

　　C++程序结构的组成

　　C++程序结构的基本组成部分

　　1 预处理命令，C++提供了三类预处理命令：宏定义命令、文件包含命令、条件编译命令。

　　2 输入输出，C++程序中总是少不了输入和输出的语句，实现与程序内部的信息交流。特别是屏幕输出的功能，几乎每个程序都要用到，使用它把计算机的结果显示在屏幕上。

　　3 函数，C++的程序是由若干个文件组成的，每个文件又是由若干个函数组成，因此，可以认为C++的程序就是函数串，即由若干个函数组成，函数与函数之间是相对的，并且是并行的，函数之间可以调用。在组成一个程序的若干个函中，必须有一个main()。

　　4 语句，语句是组成程序的基本单元。函数是由若干条语句组成的。但是，空函数是没有语句的。语句是由单词组成，单词间用空格符分隔，C++程序中的语句又是以以分号结束。语句除了有表达式语句和空语句之外，还有复合语句、分支语句、循环语句和转向语句等若干类。

　　5 变量，多数程序都需要说明和使用变量。广义讲，对象包含了变量，即将变量也称为一种对象，狭义讲，将对象看作是类的实例，对象是指某个类的对象。

　　6 其他，除了以上讲述的5个部分以外，还有其他组成部分。例如，符号常量和注释信息也是程序的一部分。C++中都尽量把常量定义为符号常量，在C++的程序中出现的是符号常量，该符号常量代表着某个确定的常量值。

　　C++程序的书写格式

　　在编程时应该注意C++的书写格式，基本原则是：一行一般写一条语句。短语句可以一行写多个。长语句可以一条写多行。分行原则是不能将一个单词分开。用双引号引用的一个字符串也最好不分开，如果一定要分开，有的编译系统要求在行尾加续行符(“\”)

　　C++程序的实现

　　C++源程序的实现与其他高级语言源程序实现的原理是一样的。一般都要经过编辑、编译、运行。其中最要的是编译过程，C++是以编译方式实现的高级语言。C++程序的实现，必须要使用某种C++语言的编译器对程序进行编译。编译器的功能是将程序的源代码转换成为机器代码的形式，称为目标代码；然后，再使目标代码进行连接，生成可执行文件。该过程可分为三个子过程：预处理过程、编译过程(词法分析、语法分析、符号表、错误处理程序、生成目标代码)、连接过程。


C++常类型(const)

常类型是指使用类型修饰符const说明的类型，常类型的变量或对象的值是不能被更新的。因此，定义或说明常类型时必须进行初始化。

　　一般常量和对象常量

　　1. 一般常量

　　一般常量是指简单类型的常量。这种常量在定义时，修饰符const可以用在类型说明符前，也可以用在类型说明符后。如：

　　int const x=2;

　　或

　　const int x=2;

　　定义或说明一个常数组可采用如下格式：

　　<类型说明符> const <数组名>[<大小>]…

　　或者

　　const <类型说明符> <数组名>[<大小>]…

　　例如：

　　int const a[5]={1, 2, 3, 4, 5};

　　2. 常对象

　　常对象是指对象常量，定义格式如下：

　　<类名> const <对象名>

　　或者

　　const <类名> <对象名>

　　定义常对象时，同样要进行初始化，并且该对象不能再被更新，修饰符const可以放在类名后面，也可以放在类名前面。

　　常指针和常引用

　　1. 常指针

　　使用const修饰指针时，由于const的位置不同，而含意不同。下面举两个例子，说明它们的区别。

　　下面定义的一个指向字符串的常量指针：

　　char * const prt1 = stringprt1;

　　其中，ptr1是一个常量指针。因此，下面赋值是非法的。

　　ptr1 = stringprt2;

　　而下面的赋值是合法的：

　　*ptr1 = "m";

　　因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。

　　下面定义了一个指向字符串常量的指针：

　　const * ptr2 = stringprt1;

　　其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此，

　　*ptr2 = "x";

　　是非法的，而：

　　ptr2 = stringptr2;

　　是合法的。

　　所以，在使用const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者const放在*和指针名之间，后者const放在类型说明符前。

　　2. 常引用

　　使用const修饰符也可以说明引用，被说明的引用为常引用，该引用所引用的对象不能被更新。其定义格式如下：

　　const <类型说明符> & <引用名>

　　例如：

　　const double & v;

　　在实际应用中，常指针和常引用往往用来作函数的形参，这样的参数称为常参数。

　　在C++面向对象的程序设计中，指针和引用使用得较多，其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象，这样，在参数传递过程中就不需要执行拷贝初始化构造函数，这将会改善程序的运行效率。

　　下面举一例子说明常指针作函数参数的作法。

#include
const int N = 6;
void print(const int *p, int n);

void main()
{
int array[N];
for (int i=0; i cin>>array[i];
print(array, N);
}

void print(const int *p, int n)
{
cout<<"{"<<*p;
for (int i=1; i cout<<","<<*(p+i);
cout<<"}"< }


　　常成员函数

　　使用const关键字进行说明的成员函数，称为常成员函数。只有常成员函数才有资格操作常量或常对象，没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下：

　　<类型说明符> <函数名> (<参数表>) const；

其中，const是加在函数说明后面的类型修饰符，它是函数类型的一个组成部分，因此，在函数实现部分也要带const关键字。下面举一例子说明常成员函数的特征。

#include
class R
{
public:
R(int r1, int r2) { R1=r1; R2=r2; }
void print();
void print() const;
private:
int R1, R2;
};

void R::print()
{
cout< }

void R::print() const
{
cout< }

void main()
{
R a(5, 4);
a.print();
const R b(20, 52);
b.print();
}


　　该例子的输出结果为：

　　5,4
　　20;52

　　该程序的类声明了两个成员函数，其类型是不同的(其实就是重载成员函数)。有带const修饰符的成员函数处理const常量，这也体现出函数重载的特点。

　　常数据成员

　　类型修饰符const不仅可以说明成员函数，也可以说明数据成员。

　　由于const类型对象必须被初始化，并且不能更新，因此，在类中说明了const数据成员时，只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。

　　下面通过一个例子讲述使用成员初始化列表来生成构造函数。

#include
class A
{
public:
A(int i);
void print();
const int &r;
private:
const int a;
static const int b;
};

const int A::b=10;
A::A(int i):a(i), r(a)
{
}

void A::print()
{
cout< }

void main()
{
A a1(100), a2(0);
a1.print();
a2.print();
}


　　该程序的运行结果为：

　　100:10:100
　　　0:10:0

　　在该程序中，说明了如下三个常类型数据成员：

　　const int & r;

　　const int a;

　　static const int b;

　　其中，r是常int型引用，a是常int型变量，b是静态常int型变量。

　　程序中对静态数据成员b进行初始化。

　　值得注意的是构造函数的格式如下所示：

　　A(int i):a(i),r(a)
　　{
　　}

　　其中，冒号后边是一个数据成员初始化列表，它包含两个初始化项，用逗号进行了分隔，因为数据成员a和r都是常类型的，需要采用初始化格式。


浅谈C++函数的参数

函数参数的求值顺序

　　当一个函数带有多个参数时，C++语言没有规定在函数调用时实参的求值顺序。而编译器根据对代码进行优化的需要自行规定对实参的求值顺序。有的编译器规定自左至右，有的编译器规定自右至左，这种对求值顺序的不同规定，对一般参数来讲没有影响。但是，如果实参表达式中带有副作用的运算符时，就有可能产生由于求值顺序不同而造成了二义性。例如：int z = add_int(++x, x+y);,这样，在不同的编译器就有可能生产不同的结果。

　　设置参数的默认值

　　在C++语言中，允许在函数的说明或定义时给一个或多个参数指定默认值。但是，要求在一个指定了默认值的参数的右边，不能出现没有指定默认值的参数。例如：

　　　int add_int(int x, int 10);

　　在上述对函数add_int()的说明中，对该函数的最右边的一个参数指定了默认值。

　　在函数调用时，编译器按从左至右的顺序将实参与形参结合，当实参的数目不足时，编译器将按同样的顺序用说明中或定义中的默认值来补足所缺少的实参。例如，如有下列的函数调用表达式：

　　　add_int(15)

　　它将与下列调用表达式：

　　　add_int(15, 10)

　　是等价的。

　　在给某个参数指定默认值是，不仅可以是一个数值，而且还可以是任意复杂的表达式。

　　使用数组作函数参数
　
　　数组作函数参数可以分为如下三种情况：(这三种情况的结果相同，只是所采用的调用机制不同)

　　1. 形参和实参都用数组

　　调用函数的实参用数组名，被调用函数的形参用数组，这种调用的机制是形参和实参共用内存中的同一个数组。因此，在被调用函数中改变了数组中某个无素的值，对调用函数该数组的该元素值也被改变，因为它们是共用同一个数组。

　　2. 形参和实参都用对应数组的指针

　　在C++中，数组名被规定为是一个指针，该指针便是指向该数组的首元素的指针，国为它的值是该数组首元素的地址值，因此，数组名是一个常量指针。

　　实际中，形参和实参一个用指针，另一个用数组也是可以的。在使用指针时可以用数组名，也可以用另外定义的指向数组的指针。

　　3. 实参用数组名形参用引用

　　如何对数组类型使用引用方式，这里先做如下说明：先用类型定义语句定义一个int型的数组类型，如下所示：

　　typedef int array[8];

　　然后，使用array来定义数组和引用。

　　示例：

#include 
typedef int array[8];
int a[8] = {1, 3, 5, 7, 9, 11, 13};
void fun(array &b, int n)
{
for(int i=0; i b[7]+=b[i];
}

void main()
{
int m=8;
fun(a, m);
cout< }


　　该程序中，在fun()函数中，使用了引用作形参，调用时所对应的实参应该是一个数组名，这里的引用是给数组起个别名。在fun()函数中对数组b的操作，就相当于b所引用数组a的操作。在C++中，常用这种调用方式。

C++语法之函数重载

所谓函数重载是指同一个函数名可以对应着多个函数的实现。例如，可以给函数名add()定义多个函数实现，该函数的功能是求和，即求两个操作数的和。其中，一个函数实现是求两个int型数之和，另一个实现是求两个浮点型数之和，再一个实现是求两个复数的和。每种实现对应着一个函数体，这些函数的名字相同，但是函数的参数的类型不同。这就是函数重载的概念。函数重载在类和对象的应用尤其重要。

　　函数重载要求编译器能够唯一地确定调用一个函数时应执行哪个函数代码，即采用哪个函数实现。确定函数实现时，要求从函数参数的个数和类型上来区分。这就是说，进行函数重载时，要求同名函数在参数个数上不同，或者参数类型上不同。否则，将无法实现重载。

　　参数类型上不同的重载函数

　　下面举一个在参数类型不同的重载函数的例子：

#include
int add(int, int);
double add(double, double);

void main()
{
cout< cout< }

int add(int x, int y)
{
return x+y;
}

double add(double a, double b)
{
return a+b;
}


　　该程序中，main()函数中调用相同名字add的两个函数，前边一个add()函数对应的是两个int型数求和的函数实现，而后边一个add()函数对应的是两个double型数求和的函数实现。这便是函数的重载。

　　以上程序输出结果为：

　　15

　　15.5

　　参数个数上不同的重载函数

　　下面举一个在参数个数上不相同的重载函数的例子：

#include
int min(int a, int b);
int min(int a, int b, int c);
int min(int a, int b, int c, int d);

void main()
{
cout< cout< }

int min(int a, int b)
{
return a }

int min(int a, int b, int c)
{
int t = min(a, b);
return min(t,c);
}

int min(int a, int b, int c, int d)
{
int t1 = min(a, b);
int t2 = min(c, d);
return min(t1, t2);
}


　　该程序中出现了函数重载，函数名min对应有三个不同的实现，函数的区分依据参数个数不同，这里的三个函数实现中，参数个数分别为2,3和4，在调用函数时根据实参的个数来选取不同的函数实现。

　　函数重载在类和对象应用比较多，尤其是在类的多态性中。在以后我们将碰到更多的在类型不同的函数重载，尤其是在结合类的继承性和指针类型的不同，而这些都是我们以后用VC编程中经常要用到的。


C++子对象和堆对象

子对象

　　当一个类的成员是某一个类的对象时，该对象就为子对象。子对象实际就是对象成员。如：

class A
{
　public:
　　…
　private:
　　…
};
class B
　{
　　public:
　　　…
　　private:
　　　A a;
　　　…
　};


　　其中，B类中成员a就是子对象，它是A类的对象作为B类的成员。

　　在类中出现了子对象或称对象成员时，该类的构造函数要包含对子对象的初始化，通常采用成员初始化表的方法来初始化子对象。在成员初始化表中包含对子对象的初始化和对类中其他成员的初始化。下面举一例子说明成员初始化的构造。

#include

class A
{
public:
A(int i, int j) { A1=i; A2=j; }
void print() { cout< private:
int A1, A2;
};

class B
{
public:
B(int i, int j, int k):a(i, j), b(k)
{
}
void print();
private:
A a; file://子对象
int b;
};

void B::print()
{
a.print();
cout< }

void main()
{
B b(6, 7, 8);
b.print();
}


　　该程序的输出结果为：

　　6,7
　　8

　　其中，a(i, j), b(k)是成员初始化表，它有二项，前一项是给子对象a初始化，其格式如下：

　　　<子对象名> (<参数表>)

　　后一项是给类B的数据成员b初始化。这一项也可以写在构造函数的函数体内，使用赋值表达式语句

　　　b = k;

　　给类B的数据成员初始化。

　　堆对象

　　所谓堆对象是指在程序运行过程中根据需要随时可以建立或删除的对象。这种堆对象被创建在内存一些空闲的存储单元中，这些存储单元被称为堆。它们可以被创建的堆对象占有，也可以通过删除堆对象而获得释放。

　　创建或删除堆对象时，需要如下两个运算符：

　　　new

　　　delete

　　这两个运算符又称为动态分配内存空间运算符。new相当于C语言中malloc()函数，而delete相当于C语言中free()函数。

　　1. 运算符new的用法

　　该运算符的功能是用来创建堆对象，或者说，它是用来动态地创建对象。

　　new运算符使用格式如下：

　　new <类型说明符> (<初始值列表>)

　　它表明在堆中建立一个由<类型说明符>给定的类型的对象，并且由括号中的<初始值列表>给出被创建对象的初始值。如果省去括号和括号中的初始值，则被创建的对象选用缺省值。

　　使用new运算符创建对象时，它可以根据其参数来选择适当的构造函数，它不用sizeof来计算对象所占的字节数，而可以计算其大小。

　　new运算符返回一个指针，指针类型将与new所分配对象相匹配，如果不匹配可以通过强制类型的方法，否则将出现编译错。

　　如果new运算符不能分配到所需要的内存，它将返回0，这时的指针为空指针。

　　运算符new也可以用来创建数组类型的对象，即对象数组。其格式如下：

　　　new <类名> [<算术表达式>]

　　其中，<算术表达式>的值为所创建的对象数组的大小。如：

　　　A *ptr;
　　　ptr = new A[5];

　　new还可用来创建一般类型的数组。如：

　　　int *p;
　　　p = new int[10];

　　使用new[]创建的对象数组或一般数组时，不能为该数组指定初始值，其初始值为缺省值。

　　2. 运算符delete的用法

　　该运算符的功能是用来删除使用new创建的对象或一般类型的指针。其格式如下：

　　　delete <指针名>

　　例如：

　　　A *ptr;
　　　ptr = new A(5, 6);
　　　delete ptr;

　　运算符delete也可用来删除使用new创建对象数组，其使用格式如下：

　　　delete[] <指针名>

　　同样，delete也可以删除由new创建的一般类型的数组。如：

　　　int *p;
　　　p = new int[10];
　　　delete[] p;

　　使用运算符delete时，应注意如下几点：

　　　(1) 它必须使用于由运算符new返回的指针；

　　　(2) 该运算符也适用于空指针(即其值为0的指针)；

　　　(3) 指针名前只用一对方括号符，并且不管所删除数组的维数，忽略方括号内的任何数字。

　　下面举一例子说明new运算符和delete运算符的使用方法。

#include

class AA
{
public:
AA(int i, int j)
{
A=i; B=j;
cout<<"构造函数.\n";
}
~AA() { cout<<"析构函数.\n"; }
void print();
private:
int A, B;
};

void AA::print()
{
cout< }

void main()
{
AA *a1, *a2;
a1 = new AA(1, 2);
a2 = new AA(5, 6);
a1->print();
a2->print();
delete a1;
delete a2;
}


　　　该程序的输出结果为：

　　　　构造函数.
　　　　构造函数.
　　　　1, 2
　　　　5, 6
　　　　构造函数.
　　　　构造函数.

　　从程序中可以看到：用new创建对象时，要调用构造函数，用delete删除对象时，要调用析构函数。如果创建或删除的时对象数组，对象数组有多少，就调用多少次构造函数或构造函数。

　　在实际应用中，经常对于new运算符返回的指针进行检验，看是否分配了有效的内存空间。结合本例给出检验方法如下：

　　if (!a1)
　　　{
　　　　cout<<"Heap erroe!\n";
　　　　exit(1);
　　　}

　　下面再举一个使用new和delete运算符对一般指针和数组的例子。

#include
#include

void fun()
{
int *p;
if (p = new int)
{
*p = 5;
cout<<*p< delete p;
}
else
cout<<"Heap error!\n";
}

void main()
{
fun();
int *pa;
pa = new int[5];
if (!pa)
{
cout<<"Heap error!\n";
exit(1);
}
for (int i=0; i<5; i++)
pa[i] = i+1;
for (i=0; i<5; i++)
cout<<pa[i]<<" ";
cout< delete[] pa;
}


局部类和嵌套类

局部类

　　在一个函数体内定义的类称为局部类。局部类中只能使用它的外围作用域中的对象和函数进行联系，因为外围作用域中的变量与该局部类的对象无关。在定义局部类时需要注意：局部类中不能说明静态成员函数，并且所有成员函数都必须定义在类体内。在实践中，局部类是很少使用的。下面是一个局部类的例子。

int a;
void fun()
{
　　static int s;
　　class A
　　　{
　　　　public:
　　　　　void init(int i) { s = i; }
　　　　};
　　A m;
　　m.init(10);
}


　　嵌套类

　　在一个类中定义的类称为嵌套类，定义嵌套类的类称为外围类。

　　定义嵌套类的目的在于隐藏类名，减少全局的标识符，从而限制用户能否使用该类建立对象。这样可以提高类的抽象能力，并且强调了两个类(外围类和嵌套类)之间的主从关系。下面是一个嵌套类的例子：

class A
{
　public:
　class B
　　{　
　　　public:
　　　　…
　　　private:
　　　　…
　　};
　void f();
　private:
　int a;
}


　　其中，类B是一个嵌套类，类A是外围类，类B定义在类A的类体内。

　　对嵌套类的若干说明：

　　1、从作用域的角度看，嵌套类被隐藏在外围类之中，该类名只能在外围类中使用。如果在外围类的作用域内使用该类名时，需要加名字限定。

　　2、从访问权限的角度来看，嵌套类名与它的外围类的对象成员名具有相同的访问权限规则。不能访问嵌套类的对象中的私有成员函数，也不能对外围类的私有部分中的嵌套类建立对象。

　　3、嵌套类中的成员函数可以在它的类体外定义。

　　4、嵌套类中说明的成员不是外围类中对象的成员，反之亦然。嵌套类的成员函数对外围类的成员没有访问权，反之亦然。国此，在分析嵌套类与外围类的成员访问关系时，往往把嵌套类看作非嵌套类来处理。这样，上述的嵌套类可写成如下格式：

class A
{
　public:
　void f();
　private:
　int a;
　};

class B
{
　public:
　　…
　private:
　　…
};


　　由引可见，嵌套类仅仅是语法上的嵌入。

　　5、在嵌套类中说明的友元对外围类的成员没有访问权。

　　6、如果嵌套类比较复杂，可以只在外围类中对嵌套类进行说明，关于嵌套的详细的内容可在外围类体外的文件域中进行定义。


C++单继承

在《基类和派生类》中讲述了单继承的基本概念，这节着重讲述继承的具体应用。

　　在单继承中，每个类可以有多个派生类，但是每个派生类只能有一个基类，从而形成树形结构。

　　成员访问权限的控制

　　在《基类和派生类》一讲中，我们讲述了派生类和派生类的对象对基类成员的访问权限的若干规定，这里通过一个实例进一步讨论访问权限的具体控制，然后得出在使用三种继承方式时的调用方法。

//继承性的public继承方式的访问权限的例子
#include

file://定义基类A
class A
{
public:
A() { cout<<"类A的构造函数！"< A(int a) { Aa = a, aa = a, aaa = a; }
void Aprint() { cout<<"类A打印自己的private成员aa:"< int Aa;
private:
int aa;
protected:
int aaa;
};

file://定义由基类A派生的类B
class B : public A
{
public:
B() { cout<<"类B的构造函数！"< B(int i, int j, int k);
void Bprint() { cout<<"类B打印自己的private成员bb和protected成员bbb:"< void B_Aprint() { cout<<"类B的public函数访问类A的public数据成员Aa:"< cout<<"类B的public函数访问类A的protected数据成员aaa:"< GetAaaa();
GetAaaa1();}
private:
int bb;
void GetAaaa() { cout<<"类B的private函数访问类A的public数据成员Aa:"< cout<<"类B的private函数访问类A的protected数据成员aaa:"< protected:
int bbb;
void GetAaaa1() { cout<<"类B的protected函数访问类A的public数据成员Aa:"< cout<<"类B的protected函数访问类A的protected数据成员aaa:"< };

file://基类B的构造函数，需负责对基类A的构造函数的初始化
B::B(int i, int j, int k):A(i), bb(j), bbb(k) {}

file://程序主函数
void main()
{
B b1(100, 200, 300); file://定义类B的一个对象b1，并初始化构造函数和基类构造函数
b1.B_Aprint(); file://类B调用自己的成员函数B_Aprint函数
b1.Bprint(); file://类B对象b1访问自己的private和protected成员
b1.Aprint(); file://通过类B的对象b1调用类A的public成员函数
}


　　该程序的输出结果为：

　　　类B的public函数访问类A的public数据成员Aa:100

　　　类B的public函数访问类A的protected数据成员aaa:100

　　　类B的private函数访问类A的public数据成员Aa:100

　　　类B的private函数访问类A的protected数据成员aaa:100

　　　类B的protected函数访问类A的public数据成员Aa:100

　　　类B的protected函数访问类A的protected数据成员aaa:100

　　　类B打印自己的private成员bb和protected成员bbb:200,300

　　　类A打印自己的private成员aa:100

　　上述是属public继承方式，我们可以得出以下结论：

　　在公有继承(public)时，派生类的public、private、protected型的成员函数可以访问基类中的公有成员和保护成员；派生类的对象仅可访问基类中的公有成员。

　　让我们把继承方式public改为private，编译结果出现1处如下错误：

　　　'Aprint' : cannot access public member declared in class 'A'

　　出错语句在于：b1.Aprint();,因此，我们可以得出以下结论：

　　在公有继承(private)时，派生类的public、private、protected型的成员函数可以访问基类中的公有成员和保护成员；但派生类的对象不可访问基类中的任何成员。另，使用class关键字定义类时，缺省的继承方式是private，也就是说，当继承方式为私有继承时，可以省略private。

　　让我们把继承方式public改为protected，可以看出，结果和private继承方式一样。

　　构造函数和析构函数

　　派生类的构造函数和析构函数的构造是讨论的主要问题，读者要掌握它。

　　1. 构造函数

　　我们已知道，派生类的对象的数据结构是由基类中说明的数据成员和派生类中说明的数据成员共同构成。将派生类的对象中由基类中说明的数据成员和操作所构成的封装体称为基类子对象，它由基类中的构造函数进行初始化。

　　构造函数不能够被继承，因此，派生类的构造函数必须通过调用基类的构造函数来初始化基类子对象。所以，在定义派生类的构造函数时除了对自己的数据成员进行初始化外，还必须负责调用基类构造函数使基类数据成员得以初始化。如果派生类中还有子对象时，还应包含对子对象初始化的构造函数。

　　派生类构造函数的一般格式如下：

　　<派生类名>(<派生类构造函数总参数表>):<基类构造函数>(参数表1),<子对象名>(<参数表2>)
　　{
　　<派生类中数据成员初始化>
　　};

　　派生类构造函数的调用顺序如下：

　　　· 基类的构造函数

　　　· 子对象类的构造函数(如果有的话)

　　　· 派生类构造函数

　　在前面的例子中，B::B(int i, int j, int k):A(i), bb(j), bbb(k)就是派生类构造函数的定义，下面再举一个构造派生类构造函数的例子。

#include
class A
{
public:
A() { a=0; cout<<"类A的缺省构造函数.\n"; }
A(int i) { a=i; cout<<"类A的构造函数.\n"; }
~A() { cout<<"类A的析构函数.\n"; }
void Print() const { cout< int Geta() { reutrn a; }
private:
int a;
}
class B : public A
{
public:
B() { b=0; cout<<"类B的缺省构造函数.\n"; }
B(int i, int j, int k);
~B() { cout<<"类B的析构函数.\n"; }
void Print();
private:
int b;
A aa;
}
B::B(int i, int j, int k):A(i), aa(j)
{
b=k;
cout<<"类B的构造函数.\n";
}
void B::Print()
{
A::Print();
cout< }

void main()
{
B bb[2];
bb[0] = B(1, 2, 5);
bb[1] = B(3, 4, 7);
for(int i=0; i<2; i++)
bb[i].Print();
}


　　2. 构造函数

　　当对象被删除时，派生类的析构函数被执行。由于析构函数也不能被继承，因此在执行派生类的析构函数时，基类的析构函数也将被调用。执行顺序是先执行派生类的构造函数，再执行基类的析构函数，其顺序与执行构造函数时的顺序正好相反。这一点从前面讲过的例子可以看出，请读者自行分析。

　　3. 派生类构造函数使用中应注意的问题

　　(1) 派生类构造函数的定义中可以省略对基类构造函数的调用，其条件是在基类中必须有缺省的构造函数或者根本没有定义构造函数。当然，基类中没有定义构造函数，派生类根本不必负责调用基类的析构函数。

　　(2) 当基类的构造函数使用一个或多个参数时，则派生类必须定义构造函数，提供将参数传递给基类构造函数途径。在有的情况下，派生类构造函数的函数体可能为空，仅起到参数传递作用。如本讲第一个例子就属此种情况。

　　子类型化和类型适应

　　1. 子类型化

　　子类型的概念涉及到行为共享，它与继承有着密切关系。

　　有一个特定的类型S，当且仅当它至少提供了类型T的行为，由称类型S是类型T的子类型。子类型是类型之间的一般和特殊的关系。

　　在继承中，公有继承可以实现子类型。例如：

class A
{
public:
void Print() const { cout<<"A::print() called.\n"; }
};
class B : public A
{
public:
void f() {}
};


　　类B继承了类A，并且是公有继承方式。因此，可以说类B是类A的一个子类型。类A还可以有其他的子类型。类B是类A的子类型，类B具备类A中的操作，或者说类A中的操作可被用于操作类B的对象。

　　子类型关系是不可逆的。这就是说，已知B是A的子类型，而认为A也是B的子类型是错误的，或者说，子类型关系是不对称不。

　　因此，可以说公有继承可以实现子类型化。

　　2. 类型适应

　　类型适应是指两种类型之间的关系。例如，B类型适应A类型是指B类型的对象能够用于A类型的对象所能使用的场合。

　　前面讲过的派生类的对象可以用于基类对象所能使用的场合，我们说派生类适应于基类。

　　同样道理，派生类对象的指针和引用也适应于基类对象的指针和引用。

　　子类型化与类型适应是致的。A类型是B类型的子类型，那么A类型必将适应于B类型。

　　子类型的重要性就在于减轻程序人员编写程序代码的负担。因为一个函数可以用于某类型的对象，则它也可以用于该类型的各个子类型的对象，这样就不必为处理这些子类型的对象去重载该函数。


C++多继承

　

多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类，派生类与每个基类之间的关系仍可看作是一个单继承。

　　多继承下派生类的定义格式如下：

　　class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
　　　{
　　　　<派生类类体>
　　　};

　　其中，<继承方式1>,<继承方式2>,…是三种继承方式：public、private、protected之一。例如：

class A
{
…
};
class B
{
…
};
class C : public A, public, B
{
…
};


其中，派生类C具有两个基类(类A和类B)，因此，类C是多继承的。按照继承的规定，派生类C的成员包含了基类B中成员以及该类本身的成员。

　　多继承的构造函数

　　在多继承的情况下，派生类的构造函数格式如下：

　　<派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>),…
　　　<子对象名>(<参数表n+1>),…
　　　　{
　　　　　<派生类构造函数体>
　　　　}

　　其中，<总参数表>中各个参数包含了其后的各个分参数表。

　　多继承下派生类的构造函数与单继承下派生类构造函数相似，它必须同时负责该派生类所有基类构造函数的调用。同时，派生类的参数个数必须包含完成所有基类初始化所需的参数个数。

　　派生类构造函数执行顺序是先执行所胡基类的构造函数，再执行派生类本身构造函数，处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序，与派生类构造函数中所定义的成员初始化列表的各项顺序无关。也就是说，执行基类构造函数的顺序取决于定义派生类时基类的顺序。可见，派生类构造函数的成员初始化列表中各项顺序可以任意地排列。
　
　　下面通过一个例子来说明派生类构造函数的构成及其执行顺序。

#include
class B1
{
public:
B1(int i)
{
b1 = i;
cout<<"构造函数 B1."< }
void print() { cout< private:
int b1;
};

class B2
{
public:
B2(int i)
{
b2 = i;
cout<<"构造函数 B2."< }
void print() { cout< private:
int b2;
};

class B3
{
public:
B3(int i)
{
b3 = i;
cout<<"构造函数 B3."< }
int getb3() { return b3; }
private:
int b3;
};
class A : public B2, public B1
{
public:
A(int i, int j, int k, int l):B1(i), B2(j), bb(k)
{
a = l;
cout<<"构造函数 A."< }
void print()
{
B1::print();
B2::print();
cout< }
private:
int a;
B3 bb;
};

void main()
{
A aa(1, 2, 3, 4);
aa.print();
}


　　该程序的输出结果为：

　　　构造函数 B2.2

　　　构造函数 B1.1

　　　构造函数 B3.3

　　　构造函数 A.4

　　　1

　　　2

　　　4, 3

　　在该程序中，作用域运算符::用于解决作用域冲突的问题。在派生类A中的print()函数的定义中，使用了B1::print;和B2::print();语句分别指明调用哪一个类中的print()函数，这种用法应该学会。

C++多继承

8/27/2001 8:37:55· ·--··pcvc


上一页　1 2　


　　二义性问题

　　一般说来，在派生类中对基类成员的访问应该是唯一的，但是，由于多继承情况下，可能造成对基类中某成员的访问出现了不唯一的情况，则称为对基类成员访问的二义性问题。

　　实际上，在上例已经出现过这一问题，回忆一下上例中，派生类A的两基类B1和B2中都有一个成员函数print()。如果在派生类中访问print()函数，到底是哪一个基类的呢？于是出现了二义性。但是在上例中解决了这个问题，其办法是通过作用域运算符::进行了限定。如果不加以限定，则会出现二义性问题。

　　下面再举一个简单的例子，对二义性问题进行深入讨论。例如：

class A
{
public:
void f();
};

class B
{
public:
void f();
void g();
};

class C : public A, public B
{
public:
void g();
void h();
};


　　如果定义一个类C的对象c1:

　　　C c1;

　　则对函数f()的访问

　　　c1.f();

　　便具有二义性：是访问类A中的f()，还是访问类B中的f()呢？

　　解决的方法可用前面用过的成员名限定法来消除二义性，例如：

　　　c1.A::f();

　　或者

　　　c1.B::f();

　　但是，最好的解决办法是在类C中定义一个同名成员f()，类C中的f()再根据需要来决定调用A::f()，还是B::f()，还是两者皆有，这样，c1.f()将调用C::f()。

　　同样地，类C中成员函数调用f()也会出现二义性问题。例如：

　　viod C::h()
　　　{
　　　　f();
　　　}

　　这里有二义性问题，该函数应修改为：

　　　void C::h()
　　　{
　　　　A::f();
　　　}

　　或者

　　　void C::h()
　　　{
　　　　B::f();
　　　}

　　或者

　　　void C::f()
　　　{
　　　　A::f();
　　　　B::f();
　　　}

　　另外，在前例中，类B中有一个成员函数g()，类C中也有一个成员函数g()。这时，

　　　c1.g();

　　不存在二义性，它是指C::g()，而不是指B::g()。因为这两个g()函数，一个出现在基类B，一个出现在派生类C，规定派生类的成员将支配基类中的同名成员。因此，上例中类C中的g()支配类B中的g()，不存在二义性，可选择支配者的那个名字。

　　当一个派生类从多个基类派生类，而这些基类又有一个共同的基类，则对该基类中说明的成员进行访问时，也可能会出现二义性。例如：

class A
{
public:
int a;
};
class B1 : public A
{
private:
int b1;
};
class B2 : public A
{
private:
int b2;
};
class C : public B1, public B2
{
public:
int f();
private:
int c;
};


　　已知：C c1;

　　下面的两个访问都有二义性：

　　c1.a;
　　c1.A::a;

　　而下面的两个访问是正确的：

　　c1.B1::a;
　　c1.B2::a;

　　类C的成员函数f()用如下定义可以消除二义性：

　　int C::f()
　　　{
　　　　retrun B1::a + B2::a;
　　　}

　　由于二义性的原因，一个类不可以从同一个类中直接继承一次以上，例如：

　　class A : public B, public B
　　　{
　　　　…
　　　}

　　这是错误的。


C++ 对象与数组

对象数组是指数组元素为对象的数组。该数组中若干个元素必须是同一个类的若干个对象。对象数组的定义、赋值和引用与普通数组一样，只是数组的元素与普通数组不同，它是同类的若干个对象。

　　1. 对象数组的定义

　　对象数组定义格式如下：

　　　<类名><数组名>[<大小>]...

　　其中，<类名>指出该数组元素是属于该类的对象，方括号内的<大小>给出某一维的元素个数。一维对象数组只有一个方括号，二维对象数组要有两个方括号，等等，例如：

　　　DATE dates[7];

　　表明dates是一维对象数组名，该数组有7个元素，每个元素都是类DATE的对象。

　　2. 对象数组的赋值

　　对象数组可以被赋初值，也可以被赋值。例如：

class DATE
{
　public:
　　DATE(int m, int d, int y);
　　void printf();
　private:
　　int month, day, year;
};


　　下面是定义对象数组并赋初值和赋值：

　　　DATE dates[4]={ DATE(7, 7, 2001), DATE(7, 8, 2001), DATE(7, 9, 2001), DATE(7, 10, 2001) }

　　或者

　　　dates[0] = DATE(7, 7, 2001);
　　　dates[1] = DATE(7, 8, 2001);
　　　dates[2] = DATE(7, 9, 2001);
　　　dates[3] = DATE(7, 10, 2001);

指向数组的指针和指针数组

　　指向数组的指针和指针数组是两个完全不同的概念，现放在一起介绍是中为两者在定义格式相似，千万不要把它们搞混了。

　　1. 指向数组的指针

　　指向一般数组的指针定义格式如下：

　　　<类型说明符>(*<指针名>)[<大小>]...

　　其中，用来说明指针的 * 要与<指针名>括在一起。后面用一个方括号表示该指针指向一维数组，后面用二个方括号表示该指针指向二维数组。<类型说明符>用来说明指针所指向的数组的元素的类型。例如：

　　　int (*P)[3];

　　P是一个指向一维数组的指针，该数组有3个int型元素。

　　而指向对象数组的指针，则把<类型说明符>改为<类名>即可：

　　　<类名>(*<指针名>)[<大小>]...

　　指向数组的指针的主要应用思想是：将数组的首地址(二维数组的某个行地址)赋给指针，然后通过循环(for)改变指针指向的地址，从而动态的访问数组中各个元素。

　　2. 指针数组

　　所谓指针数组指的是数组元素为指针的那类数组。一个数组的元素可以是指向同一类型的一般指针，也可以是指向同一类类型的对象。

　　一般指针数组的定义格式如下：

　　　<类型名>*<数组名>[<大小>]...

　　其中，*加在<数组名>前面表示该数组为指针数组。[<大小>]表示某一维的大小，即该维的元素个数，…表示可以是多维指针数组，每一个[<大小>]表示一维。例如：

　　　int * pa[3];
　　　char * pc[2][5];

　　在C++编程中，经常使用char型的指针数组用来存放若干个字符串。下面是一个一维指针数组的例子。

#include 
#include 

const int N = 5;

void main()
{
char *strings[N]; file://定义一个一维指针数组strings
char str[80];
cout<<"At each prompt, enter a string:\n";
for (int i=0; i {
cout<<"Enter a string #"< cin.getline(str, sizeof(str));
strings[i] = new char[strlen(str) + 1];
strcpy(strings[i], str);
}
cout< for (i=0; i cout<<"String #"< }


　　对象指针数组的定义如下：

　　对象指针数组是指该数组的元素是指向对象的指针，它要求所有数组元素都是指向同一个类类型的对象的指针。格式如下：

　　<类名>*<数组名>[<大小>]...

　　它与前面讲过的一般的指针数组所不同的地方仅在于该数组一定是指向对象的指针。即指向对象的指针用来作该数组的元素。下面通过一个例子看一下对象指针数组的用法。

#include 
class A
{
public:
A(int i=0, int j=0) { a=i; b=j; }
void print();
private:
int a, b;
};

void A::print()
{
cout< }

void main()
{
A a1(7, 8), a2, a3(5, 7);
A *b[3] = { &a3, &a2, &a1 };
for (int i=0; i<3; i++)
b[i]->print();
}


　　带参数的main()参数

　　前面讲过的main()函数都是不带参数的。在实际编程中，有时需要main()带参数。通过main()函数的参数给程序增加一些处理信息。一般地说，当使用C++编写的源程序经过编译连接生成的可执行文件在执行时，需要还命令行参数，由该源程序的主函数main()就需要带参数。使用所还有的参数来存放命令行中的参数，以便在程序中对命令行参数进行处理。

　　带有参数的main()函数头格式如下：

　　　void main(int argc, char * argv[])

　　其中，第一个参数argc是int型的，它用来存放命令行参数的个数，实际上argc所存放的数值比命令行参数的个数多1，即将命令字(可执行文件名)也计算在内。第二个参数argv是一个一维的一级指针数组，它是用来存放命令行中各个参数和命令字的字符串的，并且规定：

　　argv[0]存放命令字

　　argv[1]存放命令行中第一个参数

　　argv[2]存放命令行中第二个参数

　　…

　　这里，argc的值和argv[]各元素的值都是系统自动组赋值的。

　　在这里讲述带参数的main()函数实际上是对指针数组应用的一个具体实例。

#include 
void main(int argc, char *argv[])
{
cout<<"The number of command line arguments is:"< cout<<"The program name is:"< if (argc>1)
{
cout<<"The command line arguments:\n";
for (int i=1; i cout< }
}


　　上述编译连接后的EXE文件，可在DOS命令行下调试。

　　关于命令行参数的使用，其基本方法是直接引用指针数组argv[]中某个元素所存放的字符串，可用下标方式，也可用指针方式。

C++ 类的静态成员(static)

静态成员的提出是为了解决数据共享的问题。实现共享有许多方法，如：设置全局性的变量或对象是一种方法。但是，全局变量或对象是有局限性的。这一章里，我们主要讲述类的静态成员来实现数据的共享。

　　静态数据成员

　　在类中，静态成员可以实现多个对象之间的数据共享，并且使用静态数据成员还不会破坏隐藏的原则，即保证了安全性。因此，静态成员是类的所有对象中共享的成员，而不是某个对象的成员。

　　使用静态数据成员可以节省内存，因为它是所有对象所公有的，因此，对多个对象来说，静态数据成员只存储一处，供所有对象共用。静态数据成员的值对每个对象都是一样，但它的值是可以更新的。只要对静态数据成员的值更新一次，保证所有对象存取更新后的相同的值，这样可以提高时间效率。

　　静态数据成员的使用方法和注意事项如下：

　　1、静态数据成员在定义或说明时前面加关键字static。

　　2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下：

　　　　<数据类型><类名>::<静态数据成员名>=<值>

　　这表明：

　　　　　(1) 初始化在类体外进行，而前面不加static，以免与一般静态变量或对象相混淆。

　　(2) 初始化时不加该成员的访问权限控制符private，public等。

　　(3) 初始化时使用作用域运算符来标明它所属类，因此，静态数据成员是类的成员，而不是对象的成员。

　　3、静态数据成员是静态存储的，它是静态生存期，必须对它进行初始化。

　　4、引用静态数据成员时，采用如下格式：

　　　<类名>::<静态成员名>

　　如果静态数据成员的访问权限允许的话(即public的成员)，可在程序中，按上述格式来引用静态数据成员。

　　下面举一例子，说明静态数据成员的应用：

#include
class Myclass
{
public:
Myclass(int a, int b, int c);
void GetNumber();
void GetSum();
private:
int A, B, C;
static int Sum;
};

int Myclass::Sum = 0;

Myclass::Myclass(int a, int b, int c)
{
A = a;
B = b;
C = c;
Sum += A+B+C;
}

void Myclass::GetNumber()
{
cout<<"Number="< }

void Myclass::GetSum()
{
cout<<"Sum="< }

void main()
{
Myclass M(3, 7, 10),N(14, 9, 11);
M.GetNumber();
N.GetNumber();
M.GetSum();
N.GetSum();
}


　　从输出结果可以看到Sum的值对M对象和对N对象都是相等的。这是因为在初始化M对象时，将M对象的三个int型数据成员的值求和后赋给了Sum，于是Sum保存了该值。在初始化N对象时，对将N对象的三个int型数据成员的值求和后又加到Sum已有的值上，于是Sum将保存另后的值。所以，不论是通过对象M还是通过对象N来引用的值都是一样的，即为54。




　　静态成员函数

　　静态成员函数和静态数据成员一样，它们都属于类的静态成员，它们都不是对象成员。因此，对静态成员的引用不需要用对象名。

　　在静态成员函数的实现中不能直接引用类中说明的非静态成员，可以引用类中说明的静态成员。如果静态成员函数中要引用非静态成员时，可通过对象来引用。下面通过例子来说明这一点。

#include
class M
{
public:
M(int a) { A=a; B+=a;}
static void f1(M m);
private:
int A;
static int B;
};

void M::f1(M m)
{
cout<<"A="< cout<<"B="< }

int M::B=0;
void main()
{
M P(5),Q(10);
M::f1(P); file://调用时不用对象名
M::f1(Q);
}


　　读者可以自行分析其结果。从中可看出，调用静态成员函数使用如下格式：

　　　<类名>::<静态成员函数名>(<参数表>);


C++ 虚基类

在《多继承》中讲过的例子中，由类A，类B1和类B2以及类C组成了类继承的层次结构。在该结构中，类C的对象将包含两个类A的子对象。由于类A是派生类C两条继承路径上的一个公共基类，那么这个公共基类将在派生类的对象中产生多个基类子对象。如果要想使这个公共基类在派生类中只产生一个基类子对象，则必须将这个基类设定为虚基类。

　　虚基类的引入和说明

　　前面简单地介绍了要引进虚基类的原因。实际上，引进虚基类的真正目的是为了解决二义性问题。

　　虚基类说明格式如下：

　　　virtual <继承方式><基类名>

　　其中，virtual是虚类的关键字。虚基类的说明是用在定义派生类时，写在派生类名的后面。例如：

class A
{
　public:
　　void f();
　　protected:
　　int a;
　};
class B : virtual public A
{
　　protected:
　　int b;
　};
class C : virtual public A
{
　　protected:
　　int c:
　};
class D : public B, public C
{
　　public:
　　int g();
　　private:
　　int d;
};


　　由于使用了虚基类，使得类A，类B，类C和类D之间关系用DAG图示法表示如下：

A{ f(), a }
/ \
B{b} C{c}
\ /
D{g(),d}

从该图中可见不同继承路径的虚基类子对象被合并成为一个对象。这便是虚基类的作用，这样将消除了合并之前可能出现的二义性。这时，在类D的对象中只存在一个类A的对象。因此，下面的引用都是正确的：

　　D n;

　　n.f(); file://对f()引用是正确的。

　void D::g()

　{
　　f(); file://对f()引用是正确的。
　}

　　下面程序段是正确的。

　　D n;
　　A *pa;
　　pa = &n;

　　其中，pa是指向类A对象的指针，n是类D的一个对象，&n是n对象的地址。pa=&n是让pa指针指向类D的对象，这是正确的，并且也无二义性。
C++ 虚基类 

9/3/2001 8:22:51· ·--··pcvc


上一页　1 2　


　　虚基类的构造函数

　　前面讲过，为了初始化基类的子对象，派生类的构造函数要调用基类的构造函数。对于虚基类来讲，由于派生类的对象中只有一个虚基类子对象。为保证虚基类子对象只被初始化一次，这个虚基类构造函数必须只被调用一次。由于继承结构的层次可能很深，规定将在建立对象时所指定的类称为最派生类。C++规定，虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。如果一个派生类有一个直接或间接的虚基类，那么派生类的构造函数的成员初始列表中必须列出对虚基类构造函数的调用。如果未被列出，则表示使用该虚基类的缺省构造函数来初始化派生类对象中的虚基类子对象。

　　从虚基类直接或间接继承的派生类中的构造函数的成员初始化列表中都要列出这个虚基类构造函数的调用。但是，只有用于建立对象的那个最派生类的构造函数调用虚基类的构造函数，而该派生类的基类中所列出的对这个虚基类的构造函数调用在执行中被忽略，这样便保证了对虚基类的对象只初始化一次。

　　C++又规定，在一个成员初始化列表中出现对虚基类和非虚基类构造函数的调用，则虚基类的构造函数先于非虚基类的构造函数的执行。

　　下面举一例子说明具有虚基类的派生类的构造函数的用法。

#include 
class A
{
public:
A(const char *s) { cout< ~A() {}
};

class B : virtual public A
{
public:
B(const char *s1, const char *s2):A(s1)
{
cout< }
};

class C : virtual public A
{
public:
C(const char *s1, const char *s2):A(s1)
{
cout< }
};

class D : public B, public C
{
public:
D(const char *s1, const char *s2, const char *s3, const char *s4)
:B(s1, s2), C(s1, s3), A(s1)
{
cout< }
};

void main()
{
D *ptr = new D("class A", "class B", "class C", "class D");
delete ptr;
}


　　该程序的输出结果为：

　　class A
　　class B
　　class C
　　class D

　　在派生类B和C中使用了虚基类，使得建立的D类对象只有一个虚基类子对象。

　　在派生类B，C，D的构造函数的成员初始化列表中都包含了对虚基类A的构造函数。

　　在建立类D对象时，只有类D的构造函数的成员初始化列表中列出的虚基类构造函数被调用，并且仅调用一次，而类D基类的构造函数的成员初始化列表中列出的虚基类构造函数不被执行。这一点将从该程序的输出结果可以看出。

　

　

<img src ="http://www.blogjava.net/bcims/aggbug/28332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/bcims/" target="_blank">bcims</a> 2006-01-17 19:41 <a href="http://www.blogjava.net/bcims/archive/2006/01/17/28332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>