﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-乱八七糟的代码-随笔分类-C/C++</title><link>http://www.cppblog.com/zqsand/category/12848.html</link><description>啥是子标题</description><language>zh-cn</language><lastBuildDate>Mon, 05 Apr 2010 09:07:03 GMT</lastBuildDate><pubDate>Mon, 05 Apr 2010 09:07:03 GMT</pubDate><ttl>60</ttl><item><title>关于对齐</title><link>http://www.cppblog.com/zqsand/archive/2010/04/04/111589.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sun, 04 Apr 2010 08:00:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/04/04/111589.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/111589.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/04/04/111589.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/111589.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/111589.html</trackback:ping><description><![CDATA[
<p><font face="YaHei Consolas Hybrid" size="4"></font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">数据对齐：是指数据所在的内存地址必须是该数据长度的整数倍。处理器可以直接访问对齐的数据，而访问未对齐的数据会在内部进行一系列的调整，虽然可以正常处理，但是会降低运行速度。例如一个处理器总线宽度为64位，那么地址必须为8的倍数，也就是一次取出8个字节。如果我们可以保证所有double地址都为8的倍数，那么可以用一个存储器操作来读或者写double了，否则我们可能需要执行两次存储器访问，因为对象可能位于两个8字节存储器块中</font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">对于结构体也是一样的例如 struct s2{int i;int j;char c;}; 如果我们把这个结构打包成9个字节，只要保证起始地址满足4的对齐要求我们就可以保证i j的对齐，不过如果我们声明了一个数组，那么元素地址成为 xd,xd+9,xd+18,xd+27 不满足对齐了。因此我们呢要分配12个字节给这个结构体</font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">更进一步 ：</font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">未对齐的数据会以不同方式给cpu带来麻烦~</font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">1.如果一个变量被划分到两个缓存行，那么我们需要访问两个缓存行才可以。</font></p> <p><font face="YaHei Consolas Hybrid" color="#8e9768" size="3">2.一些simd指令总是要求对齐的指令，对于未对齐的指令，数据对齐也会影响这些指令的使用。</font></p><img src ="http://www.cppblog.com/zqsand/aggbug/111589.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-04-04 16:00 <a href="http://www.cppblog.com/zqsand/archive/2010/04/04/111589.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>USACO 4.2.2 第一道网络流&amp;middot;&amp;middot;&amp;middot;&amp;middot;</title><link>http://www.cppblog.com/zqsand/archive/2010/03/26/110584.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Fri, 26 Mar 2010 05:04:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/26/110584.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/110584.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/26/110584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/110584.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/110584.html</trackback:ping><description><![CDATA[<p><b>Drainage Ditches</b><br><b>Hal Burch</b>  <p>Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.  <p>Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network. Note however, that there can be more than one ditch between two intersections.  <p>Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.  <h5>PROGRAM NAME: ditch</h5> <h5>INPUT FORMAT</h5> <p>Line 1:<br>Two space-separated integers, N (0 &lt;= N &lt;= 200) and M (2 &lt;= M &lt;= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream.  <p>Line 2..N+1:<br>Each of N lines contains three integers, S<sub>i</sub>, E<sub>i</sub>, and C<sub>i</sub>. S<sub>i</sub> and E<sub>i</sub> (1 &lt;= S<sub>i</sub>, E<sub>i</sub> &lt;= M) designate the intersections between which this ditch flows. Water will flow through this ditch from S<sub>i</sub> to E<sub>i</sub>. C<sub>i</sub> (0 &lt;= C<sub>i</sub> &lt;= 10,000,000) is the maximum rate at which water will flow through the ditch.  <h5>SAMPLE INPUT (file ditch.in)</h5><pre>5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
</pre>
<h5>OUTPUT FORMAT</h5>
<p>One line with a single integer, the maximum rate at which water may emptied from the pond. 
<h5>SAMPLE OUTPUT (file ditch.out)</h5><pre>50</pre><pre><font face="YaHei Consolas Hybrid" color="#b68c54" size="3">最基本的网络流</font></pre>
<div class="csharpcode"><pre class="alt" style="width: 100%; height: 1px"><span class="lnum">   1:  </span>#include&lt;iostream&gt;</pre><pre><span class="lnum">   2:  </span>#include&lt;fstream&gt;</pre><pre class="alt"><span class="lnum">   3:  </span>#include&lt;<span class="kwrd">string</span>&gt;</pre><pre><span class="lnum">   4:  </span>#include&lt;vector&gt;</pre><pre class="alt"><span class="lnum">   5:  </span>#include&lt;map&gt;</pre><pre><span class="lnum">   6:  </span>#include&lt;algorithm&gt;</pre><pre class="alt"><span class="lnum">   7:  </span>#include&lt;sstream&gt;</pre><pre><span class="lnum">   8:  </span>#include &lt;cstring&gt;</pre><pre class="alt"><span class="lnum">   9:  </span>#include &lt;queue&gt;</pre><pre><span class="lnum">  10:  </span><span class="kwrd">using</span> <span class="kwrd">namespace</span> std;</pre><pre class="alt"><span class="lnum">  11:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> MAXN = 220;</pre><pre><span class="lnum">  12:  </span><span class="kwrd">const</span> <span class="kwrd">int</span> infi = 0x7FFFFFFF;</pre><pre class="alt"><span class="lnum">  13:  </span> <span class="kwrd">int</span> capacity[MAXN][MAXN], prenode[MAXN], flow[MAXN];</pre><pre><span class="lnum">  14:  </span> queue&lt;<span class="kwrd">int</span>&gt; mq; </pre><pre class="alt"><span class="lnum">  15:  </span>&nbsp;</pre><pre><span class="lnum">  16:  </span><span class="kwrd">int</span> start, end, N;</pre><pre class="alt"><span class="lnum">  17:  </span><span class="kwrd">void</span> init(){</pre><pre><span class="lnum">  18:  </span>    freopen(<span class="str">"ditch.in"</span>,<span class="str">"r"</span>,stdin);</pre><pre class="alt"><span class="lnum">  19:  </span>    <span class="rem">//freopen("e:\\usaco\\ditch.in","r",stdin);</span></pre><pre><span class="lnum">  20:  </span>    start = 1;  </pre><pre class="alt"><span class="lnum">  21:  </span>    scanf(<span class="str">"%d %d"</span>,&amp;N,&amp;end); <span class="kwrd">int</span> c, s, t;</pre><pre><span class="lnum">  22:  </span>    memset(capacity,0,<span class="kwrd">sizeof</span>(capacity));</pre><pre class="alt"><span class="lnum">  23:  </span>    <span class="kwrd">for</span>(<span class="kwrd">int</span> i=0;i&lt;N;i++)</pre><pre><span class="lnum">  24:  </span>    {</pre><pre class="alt"><span class="lnum">  25:  </span>        scanf(<span class="str">"%d %d %d"</span>,&amp;c,&amp;s,&amp;t);</pre><pre><span class="lnum">  26:  </span>        capacity[c][s] += t; <span class="rem">//两个节点间不只有一条路</span></pre><pre class="alt"><span class="lnum">  27:  </span>    } </pre><pre><span class="lnum">  28:  </span>}</pre><pre class="alt"><span class="lnum">  29:  </span><span class="kwrd">int</span> bfs(){<span class="rem">//寻找增广路径</span></pre><pre><span class="lnum">  30:  </span>    <span class="kwrd">while</span>(!mq.empty()) mq.pop(); </pre><pre class="alt"><span class="lnum">  31:  </span>    mq.push(start);  <span class="rem">//源节点入队</span></pre><pre><span class="lnum">  32:  </span>    <span class="rem">//memset(flow,0,sizeof(flow));</span></pre><pre class="alt"><span class="lnum">  33:  </span>    memset(prenode,-1,<span class="kwrd">sizeof</span>(prenode)); <span class="rem">//重置前向节点</span></pre><pre><span class="lnum">  34:  </span>    prenode[start] = 0; flow[start]=infi; <span class="rem">//源节点流量无限大</span></pre><pre class="alt"><span class="lnum">  35:  </span>    <span class="kwrd">while</span>(!mq.empty()){</pre><pre><span class="lnum">  36:  </span>        <span class="kwrd">int</span> cur = mq.front(); </pre><pre class="alt"><span class="lnum">  37:  </span>        mq.pop();</pre><pre><span class="lnum">  38:  </span>        <span class="kwrd">if</span>(cur == end) <span class="kwrd">break</span>; <span class="rem">//到达汇点结束路径 </span></pre><pre class="alt"><span class="lnum">  39:  </span>        <span class="kwrd">for</span>(<span class="kwrd">int</span> i=1;i&lt;=end;i++){ </pre><pre><span class="lnum">  40:  </span>            <span class="kwrd">if</span>(prenode[i]==-1 &amp;&amp; capacity[cur][i]) <span class="rem">//访问当前节点所有未访问的相邻节点，更新flow</span></pre><pre class="alt"><span class="lnum">  41:  </span>            {</pre><pre><span class="lnum">  42:  </span>                prenode[i] = cur;</pre><pre class="alt"><span class="lnum">  43:  </span>                flow[i] = (flow[cur]&lt;capacity[cur][i]?flow[cur]:capacity[cur][i]);</pre><pre><span class="lnum">  44:  </span>                mq.push(i);</pre><pre class="alt"><span class="lnum">  45:  </span>            }</pre><pre><span class="lnum">  46:  </span>        }</pre><pre class="alt"><span class="lnum">  47:  </span>    }</pre><pre><span class="lnum">  48:  </span>    <span class="kwrd">if</span>(prenode[end]==-1)  <span class="rem">//如果未找到增广路径返回-1</span></pre><pre class="alt"><span class="lnum">  49:  </span>        <span class="kwrd">return</span> -1;</pre><pre><span class="lnum">  50:  </span>    <span class="kwrd">return</span> flow[end];</pre><pre class="alt"><span class="lnum">  51:  </span>}</pre><pre><span class="lnum">  52:  </span><span class="kwrd">int</span> Edmonds_Karp(){</pre><pre class="alt"><span class="lnum">  53:  </span>    <span class="kwrd">int</span> total = 0, pathcapacity;<span class="rem">//pathcapacity 路径增加量</span></pre><pre><span class="lnum">  54:  </span>    <span class="kwrd">while</span>((pathcapacity = bfs()) != -1){<span class="rem">//可以找到增广路径时候进行循环</span></pre><pre class="alt"><span class="lnum">  55:  </span>        <span class="kwrd">int</span> cur = end;    <span class="rem">//从汇点开始增加逆向节点</span></pre><pre><span class="lnum">  56:  </span>        <span class="kwrd">while</span>( cur != start ){</pre><pre class="alt"><span class="lnum">  57:  </span>            <span class="kwrd">int</span> t = prenode[cur] ;</pre><pre><span class="lnum">  58:  </span>            capacity[t][cur] -= pathcapacity;</pre><pre class="alt"><span class="lnum">  59:  </span>            capacity[cur][t] += pathcapacity;</pre><pre><span class="lnum">  60:  </span>            cur = t;</pre><pre class="alt"><span class="lnum">  61:  </span>        }</pre><pre><span class="lnum">  62:  </span>        total += pathcapacity;<span class="rem">//max_flow</span></pre><pre class="alt"><span class="lnum">  63:  </span>    }</pre><pre><span class="lnum">  64:  </span>    <span class="kwrd">return</span> total;</pre><pre class="alt"><span class="lnum">  65:  </span>}</pre><pre><span class="lnum">  66:  </span><span class="kwrd">void</span> output(){</pre><pre class="alt"><span class="lnum">  67:  </span>    freopen(<span class="str">"ditch.out"</span>,<span class="str">"w"</span>,stdout);</pre><pre><span class="lnum">  68:  </span>    <span class="rem">//freopen("c:\\usaco\\ditch.out","w",stdout);</span></pre><pre class="alt"><span class="lnum">  69:  </span>    cout&lt;&lt;Edmonds_Karp()&lt;&lt;endl;</pre><pre><span class="lnum">  70:  </span>} </pre><pre class="alt"><span class="lnum">  71:  </span>   <span class="kwrd">int</span> main()</pre><pre><span class="lnum">  72:  </span>{</pre><pre class="alt"><span class="lnum">  73:  </span>    init();  </pre><pre><span class="lnum">  74:  </span>    output();</pre><pre class="alt"><span class="lnum">  75:  </span>    <span class="kwrd">return</span> 0;</pre><pre><span class="lnum">  76:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p></p>
<p><font face="YaHei Consolas Hybrid" size="3">标程：使用贪心法，寻找一条增广路径的时候不断寻找cap最大的，未被访问的节点mloc；然后更新跟mloc相邻的节点flow以</font></p>
<p><font face="YaHei Consolas Hybrid" size="3">及prenode信息.最后当运行到end时候，更新路径节点capacity，同时增加max_flow.重复上述过程直到找不到增广路径</font></p>
<div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>#include &lt;stdio.h&gt;</pre><pre><span class="lnum">   2:  </span>#include &lt;<span class="kwrd">string</span>.h&gt;</pre><pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre><pre><span class="lnum">   4:  </span><span class="preproc">#define</span> MAXI 200</pre><pre class="alt"><span class="lnum">   5:  </span>&nbsp;</pre><pre><span class="lnum">   6:  </span><span class="rem">/* total drain amount between intersection points */</span></pre><pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">int</span> drain[MAXI][MAXI];</pre><pre><span class="lnum">   8:  </span><span class="kwrd">int</span> nint; <span class="rem">/* number of intersection points */</span></pre><pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre><pre><span class="lnum">  10:  </span><span class="kwrd">int</span> cap[MAXI]; <span class="rem">/* amount of flow that can get to each node */</span></pre><pre class="alt"><span class="lnum">  11:  </span><span class="kwrd">int</span> vis[MAXI]; <span class="rem">/* has this node been visited by Dijkstra's yet? */</span></pre><pre><span class="lnum">  12:  </span><span class="kwrd">int</span> src[MAXI]; <span class="rem">/* the previous node on the path from the source to here */</span></pre><pre class="alt"><span class="lnum">  13:  </span>&nbsp;</pre><pre><span class="lnum">  14:  </span><span class="kwrd">int</span> augment(<span class="kwrd">void</span>)</pre><pre class="alt"><span class="lnum">  15:  </span> { <span class="rem">/* run a Dijkstra's varient to find maximum augmenting path */</span></pre><pre><span class="lnum">  16:  </span>  <span class="kwrd">int</span> lv;</pre><pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">int</span> mloc, max;</pre><pre><span class="lnum">  18:  </span>  <span class="kwrd">int</span> t;</pre><pre class="alt"><span class="lnum">  19:  </span>&nbsp;</pre><pre><span class="lnum">  20:  </span>  memset(cap, 0, <span class="kwrd">sizeof</span>(cap));</pre><pre class="alt"><span class="lnum">  21:  </span>  memset(vis, 0, <span class="kwrd">sizeof</span>(vis));</pre><pre><span class="lnum">  22:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  23:  </span>  cap[0] = 2000000000;</pre><pre><span class="lnum">  24:  </span>  <span class="kwrd">while</span> (1)</pre><pre class="alt"><span class="lnum">  25:  </span>   {</pre><pre><span class="lnum">  26:  </span>    <span class="rem">/* find maximum unvisited node */</span></pre><pre class="alt"><span class="lnum">  27:  </span>    max = 0;</pre><pre><span class="lnum">  28:  </span>    mloc = -1;</pre><pre class="alt"><span class="lnum">  29:  </span>    <span class="kwrd">for</span> (lv = 0; lv &lt; nint; lv++)</pre><pre><span class="lnum">  30:  </span>      <span class="kwrd">if</span> (!vis[lv] &amp;&amp; cap[lv] &gt; max)</pre><pre class="alt"><span class="lnum">  31:  </span>       {</pre><pre><span class="lnum">  32:  </span>        max = cap[lv];</pre><pre class="alt"><span class="lnum">  33:  </span>    mloc = lv;</pre><pre><span class="lnum">  34:  </span>       }</pre><pre class="alt"><span class="lnum">  35:  </span>    <span class="kwrd">if</span> (mloc == -1) <span class="kwrd">return</span> 0;</pre><pre><span class="lnum">  36:  </span>    <span class="kwrd">if</span> (mloc == nint-1) <span class="kwrd">break</span>; <span class="rem">/* max is the goal, we're done */</span></pre><pre class="alt"><span class="lnum">  37:  </span>&nbsp;</pre><pre><span class="lnum">  38:  </span>    vis[mloc] = -1; <span class="rem">/* mark as visited */</span></pre><pre class="alt"><span class="lnum">  39:  </span>&nbsp;</pre><pre><span class="lnum">  40:  </span>    <span class="rem">/* update neighbors, if going through this node improves the</span></pre><pre class="alt"><span class="lnum">  41:  </span><span class="rem">       capacity */</span></pre><pre><span class="lnum">  42:  </span>    <span class="kwrd">for</span> (lv = 0; lv &lt; nint; lv++)</pre><pre class="alt"><span class="lnum">  43:  </span>      <span class="kwrd">if</span> (drain[mloc][lv] &gt; cap[lv] &amp;&amp; max &gt; cap[lv])</pre><pre><span class="lnum">  44:  </span>       {</pre><pre class="alt"><span class="lnum">  45:  </span>        cap[lv] = drain[mloc][lv];</pre><pre><span class="lnum">  46:  </span>    <span class="kwrd">if</span> (cap[lv] &gt; max) cap[lv] = max;</pre><pre class="alt"><span class="lnum">  47:  </span>    src[lv] = mloc;</pre><pre><span class="lnum">  48:  </span>       }</pre><pre class="alt"><span class="lnum">  49:  </span>   }</pre><pre><span class="lnum">  50:  </span>  max = cap[nint-1];</pre><pre class="alt"><span class="lnum">  51:  </span>&nbsp;</pre><pre><span class="lnum">  52:  </span>  <span class="rem">/* augment path, starting at end */</span></pre><pre class="alt"><span class="lnum">  53:  </span>  <span class="kwrd">for</span> (lv = nint-1; lv &gt; 0; lv = src[lv])</pre><pre><span class="lnum">  54:  </span>   {</pre><pre class="alt"><span class="lnum">  55:  </span>    t = src[lv];</pre><pre><span class="lnum">  56:  </span>    drain[t][lv] -= max;</pre><pre class="alt"><span class="lnum">  57:  </span>    drain[lv][t] += max;</pre><pre><span class="lnum">  58:  </span>   }</pre><pre class="alt"><span class="lnum">  59:  </span>  <span class="kwrd">return</span> max;</pre><pre><span class="lnum">  60:  </span> }</pre><pre class="alt"><span class="lnum">  61:  </span>&nbsp;</pre><pre><span class="lnum">  62:  </span><span class="kwrd">int</span> main(<span class="kwrd">int</span> argc, <span class="kwrd">char</span> **argv)</pre><pre class="alt"><span class="lnum">  63:  </span> {</pre><pre><span class="lnum">  64:  </span>  FILE *fout, *fin;</pre><pre class="alt"><span class="lnum">  65:  </span>  <span class="kwrd">int</span> lv;</pre><pre><span class="lnum">  66:  </span>  <span class="kwrd">int</span> num;</pre><pre class="alt"><span class="lnum">  67:  </span>  <span class="kwrd">int</span> p1, p2, c;</pre><pre><span class="lnum">  68:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  69:  </span>  <span class="kwrd">if</span> ((fin = fopen(<span class="str">"ditch.in"</span>, <span class="str">"r"</span>)) == NULL)</pre><pre><span class="lnum">  70:  </span>   {</pre><pre class="alt"><span class="lnum">  71:  </span>    perror (<span class="str">"fopen fin"</span>);</pre><pre><span class="lnum">  72:  </span>    exit(1);</pre><pre class="alt"><span class="lnum">  73:  </span>   }</pre><pre><span class="lnum">  74:  </span>  <span class="kwrd">if</span> ((fout = fopen(<span class="str">"ditch.out"</span>, <span class="str">"w"</span>)) == NULL)</pre><pre class="alt"><span class="lnum">  75:  </span>   {</pre><pre><span class="lnum">  76:  </span>    perror (<span class="str">"fopen fout"</span>);</pre><pre class="alt"><span class="lnum">  77:  </span>    exit(1);</pre><pre><span class="lnum">  78:  </span>   }</pre><pre class="alt"><span class="lnum">  79:  </span>&nbsp;</pre><pre><span class="lnum">  80:  </span>  fscanf (fin, <span class="str">"%d %d"</span>, &amp;num, &amp;nint);</pre><pre class="alt"><span class="lnum">  81:  </span>  <span class="kwrd">while</span> (num--)</pre><pre><span class="lnum">  82:  </span>   {</pre><pre class="alt"><span class="lnum">  83:  </span>    fscanf (fin, <span class="str">"%d %d %d"</span>, &amp;p1, &amp;p2, &amp;c);</pre><pre><span class="lnum">  84:  </span>    p1--;</pre><pre class="alt"><span class="lnum">  85:  </span>    p2--;</pre><pre><span class="lnum">  86:  </span>    drain[p1][p2] += c; <span class="rem">/* note += handles two ditches between same points */</span></pre><pre class="alt"><span class="lnum">  87:  </span>   }</pre><pre><span class="lnum">  88:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  89:  </span>  <span class="rem">/* max flow algorithm: augment while you can */</span></pre><pre><span class="lnum">  90:  </span>  c = 0;</pre><pre class="alt"><span class="lnum">  91:  </span>  <span class="kwrd">while</span> ((p1 = augment()))</pre><pre><span class="lnum">  92:  </span>    c += p1;</pre><pre class="alt"><span class="lnum">  93:  </span>  fprintf (fout, <span class="str">"%d\n"</span>, c);</pre><pre><span class="lnum">  94:  </span>  <span class="kwrd">return</span> 0;</pre><pre class="alt"><span class="lnum">  95:  </span> }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font>&nbsp;</p>
<p><font face="YaHei Consolas Hybrid" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/110584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-26 13:04 <a href="http://www.cppblog.com/zqsand/archive/2010/03/26/110584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探索C++对象模型读书笔记 (七)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/25/110552.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Thu, 25 Mar 2010 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/25/110552.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/110552.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/25/110552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/110552.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/110552.html</trackback:ping><description><![CDATA[<p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">最后一章~~拖了几天，得赶紧记下了~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">名字： On the cusp of the object model</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">7.1 Template</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Template用的很少，这节中的有些东西比较晦涩，挑一些能理解的记下吧。剩下的等用的多了再回头来看。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Template的具现行为 template instantiation</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Template &lt;calss T&gt;class Point{</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">&nbsp; public: enum Status{unallocated,normalized};Point(T x=0.0,T y=0.0);</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">~Point() ; void * operator new(size_t);private:static Point&lt;T&gt; *freelist</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">static int chunksize; T _x,_y;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">编译器看到这样的声明，会有什么动作？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">没有。static data 不可用 enum 不可用 ，enum虽然类型固定，但他只能和template point class 的某个实体来存取或操作。我们可以 point&lt;float&gt;::Status s;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">但是不能 point::status s; 因此我们可能想把enum抽离到一个非模板类以避免多重拷贝。同样道理，freelist 和chunksize对于程序而言也不可用。必须明确指定point&lt;float&gt;::freelist.也就是说静态数据成员是和特定类型的类绑定的而不是泛型的模板类。但是如果定义一个指针不一定会具现出相应的类，因为一个指针，并不一定指向一个class object。编译器不需要知道该class 相应的任何member 或者数据或者</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">内存布局，所以没有必要具现。但是如果是定义并初始化一个引用就真的会具现出一个实体，因为不存在空引用。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">成员函数并不应该被实体化，只有当他被调用的时候才需要被具现出来。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">template&lt;class T&gt;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">class mumble{</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">public: Muble(T t=1024):tt(t){ if(tt!=t)throw ex; }</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">private: T tt;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">上面的模板中出现错误有，t=1024 不一定成功，!= 不一定定义</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">这两个错误只有到具现操作结合具体类型才能确定出来</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">编译器面对一个template声明，在他被一组实际参数具现之前，只能实行以有限地错误检查，只有特定实体定义之后，才会发现一些与语法无关的但是十分明显的错误，这是技术上的一大问题。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Template 的名称决议方式</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">.h文件定义</font></p> <p><font color="#a9a8e3" size="3">void out(int x){<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"out_by_class_define_scrope"&lt;&lt;endl;<br>}<br>template &lt;class type&gt;<br>class A{<br>public:<br>&nbsp;&nbsp;&nbsp; void test1(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out(m1);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; void test2(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out(m2);<br>&nbsp;&nbsp;&nbsp; }<br>private:<br>&nbsp;&nbsp;&nbsp; int m1;<br>&nbsp;&nbsp;&nbsp; type m2;<br>}; </font> <p><font color="#a9a8e3" size="3">.cpp文件定义 </font> <p><font color="#a9a8e3" size="3">void out(double x){<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"out_by_class_instantiation_scrope"&lt;&lt;endl;<br>}</font></p> <p><font color="#a9a8e3" size="3">int main(）<br>{&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; A&lt;double&gt; a;<br>&nbsp;&nbsp;&nbsp; a.test1();<br>&nbsp;&nbsp;&nbsp; a.test2();</font></p> <p><font color="#a9a8e3" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">按照书中的说法，如果一个函数，参数类型和type无关的话，应该取他的scope of template declaration中定义的函数，而反之取在他的instantiation中的那个。事实上在测试中发现</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">MSVC 中 ，函数定义的决议是依照类型的，如果有合适的函数比如type是double，此时如果定义处或者具现处有double型的函数定义，那么函数就会决议为那一个定义的~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">MEMber function的具现行为：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">编译器如何确保只有一个vtable产生？ 一种方法是 每一个virtual func地址都放在vtable中，如果取得函数地址，则表示virtual func 的定义必然出现在程序的某个地点，否则程序无法连接成功。此外该函数只能有一个实体，否则也是连接不成功。那么，就把vtable放在定义了该class的第一个non-inline，nonpure virtual function的文件中吧。。（not so clear）</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">在实现层面上，template 似乎拒绝全面自动化，以手动方式在个别的object module中完成预先的具现工作是一种有效率的方法。</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">7.2异常处理</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">为了维持执行速度，编译器可以在编译时期建立起用于支持的数据结构</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">为了维持程序大小，编译器可以在执行期建立数据结构</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">c++ eH 主要由三个部分构成：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">throw语句</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">catch语句</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">try语句，这些语句可能触发catch子句起作用</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">一个exception 被抛出时候，控制权会从函数调用释放出来，并寻找一个吻合的catch，如果没有那么默认的处理例程terminate()会被调用，控制权放弃后，堆栈中的每一个函数调用也被推离。每一个函数被推离堆栈的时候，函数的local class object 的dtor也会被调用。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">在程序不同段里，由于声明不同的变量，一个区域可能因为在区域内发生exception的处理方式不同分成多个区段。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">在程序员层面，eh也改变了函数在资源上的管理。例如下面函数中更含有对一块共享内存的locking和unlocking操作 ：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">void mumble(void * arena){</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Point *p= new point ;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">smlock(arena) ; </font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">//…..如果此时一个exception发生，问题就产生了</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">sumunlock(arena);</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">delete p;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">从语义上讲，我们在函数退出堆栈之前，需要unlock共享内存并delete p，我们需要这样做：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">try{smlock(arena)} catch(…){</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">&nbsp;&nbsp;&nbsp; smunlock(arena); delete p; throw;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">new不需要放在try段里，因为，如果new发生了exception，heap中的内存并没有分配，point的ctor没有调用，如果在ctor中exception，那么piont的任何构造好的合成物也会自动解构掉，heap也会自动释放掉。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">处理这种资源管理问题，建议： 把资源需求封装在一个class object 体内，并由dtor释放资源.</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">auto_ptr&lt;point&gt; ph (new point); smlock sm(arena);//如果此时exception 没有问题</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">// 不需要明确的unlock 和delete </font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">// local dtor 会在这里被调用 sm.SMlock::~smlock(); ph.auto_ptr&lt;point&gt;::~auto_ptr&lt;point&gt;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Exception handling 的支持：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">1.检验发生throw操作的函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">2.决定throw是否发生在try区段里</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">3.如果是编译器必须把exception type 拿来和catch比较</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">4.吻合的话控制权交给catch</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">5.如果throw不发生在try段或者没有吻合的，系统会摧毁所有active local object b从堆栈把当前函数unwind掉 ，跳出到程序堆栈的下一个函数去，然后重复上述步骤</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">当一个实际对象在程序执行时被抛出，exception object会被产生出来并通常放在相同形式的exception 数据堆栈中。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">catch(expoint p){</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">&nbsp;&nbsp; //do sth </font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">&nbsp;&nbsp; throw;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">以及一个exception object 类型为 exVertex 派生自 expoint ，这两种类型都吻合，catch会怎么做</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">以exception object作为初值，像函数参数一样会有一个local copy，如果p是一个object而不是一个reference ，内容被拷贝的时候，这个object的非expoint部分会被切掉，如果有vptr 会被设定为expoint的vptr，如果被再次丢出呢？丢出p需要再产生另外一个exception 临时对象，丢出原来的异常 ，之前的修改统统作废。但是如果 catch(expoint&amp; p);怎么样呢。 任何对这个object的改变都会繁殖到之后的catch语句总。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">c++ 编译器为了支持EH付出的代价最大，某种程度是因为执行期的天性以及对底层硬件的依赖。</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">7.3 RTTI</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">RTTI是Except handling的一个附属产品，因为我们需要提供某种查询exception objects的方法，用来得到exception的实际类型。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">在向下转型问题上，如果要保证其安全性，那么必须在执行期对指针有所查询，看看它到底指向什么类型的对象。那么我们需要额外的空间存储类型信息，通常是一个指针，指某个类型信息节点。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">需要额外的时间以决定执行期的类型。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">冲突发生在：</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">1.程序员大量的使用了多台，并需要大量的downcast操作</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">2.程序员使用内建的数据类型和非多态，他不需要额外负担带来的便利</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">那么如何了解程序员的需要呢？？ 策略是一个具有多态性性质的class，也就是具有内涵继承或者声明 virtual func的类需要rtti支持。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">这样所有多态类维护一个vptr。额外负担降低到：每一个class object多花费一个指针，指针只被设定一次，而且是编译器静态设定。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">down_cast</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">if(pfct pf = dynamic_cast&lt; pfct &gt;(pt))….</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">((type_info*)(pt-&gt;vptr[0]))-&gt;type_descripter;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">Reference --------Pointer </font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">dynamic_cast执行在ptr上 失败返回0，如果实行在ref上。由于ref不能被赋予null，也就是没有空引用。如果我们把一个ref设为0会引发临时对象产生，然后用0初始化它，使ref成为这个临时对象的别名。因此此时失败了会产生一个bad_cast exception。</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">typeid的参数可以使引用，对象或者是类型</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">事实上，type_info 也适用内建类型，这对于eh机制有必要</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">例如 int ex_errno; throw ex_errno;</font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3">其中int类型 int *ptr; if(typeid(ptr) == typeid(int*));</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3"> ----------------------全书笔记到此结束 --------------------------------s</font></p> <p><font face="YaHei Consolas Hybrid"></font><font color="#a9a8e3" size="3">&nbsp;</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid"></font><font color="#a9a8e3" size="3">&nbsp;</font></p></blockquote> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid"></font><font color="#a9a8e3" size="3">&nbsp;</font></p> <blockquote> <p><font color="#a9a8e3" size="3">&nbsp;</font></p></blockquote> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <p><font color="#a9a8e3" size="3">&nbsp;</font></p> <blockquote> <p><font color="#a9a8e3" size="3">&nbsp;</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#a9a8e3" size="3"></font></p> <p><font color="#a9a8e3" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/110552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-25 21:09 <a href="http://www.cppblog.com/zqsand/archive/2010/03/25/110552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>重载操作符 (c++primer 4e)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/15/109748.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Mon, 15 Mar 2010 08:40:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/15/109748.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/109748.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/15/109748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/109748.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/109748.html</trackback:ping><description><![CDATA[<p><font face="方正准圆简体" color="#0080c0" size="4">1.为啥要重载操作符：</font></p> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">通过重载操作符，程序员可以针对“类”类型的操作数定义不同的操作符版本。良好的操作符定义可以使class类型的使用想内置类型一样直观简洁，使用重定义的操作符而不是命名函数使得程序可以用表达式代替函数调用，使程序编写和阅读更容易~</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">2.哪些不能重载</font></p> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">::&nbsp;&nbsp;&nbsp;&nbsp; .*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .&nbsp;&nbsp;&nbsp;&nbsp; ?:&nbsp;&nbsp;&nbsp; 这些不能重载</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">3.需要注意的地方：</font></p> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">重载必须有一个class类型的操作数，短路求值失去，</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">重载操作符和内置操作符结合型相同，优先级操作数个数均相同</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">不要重载一些含有内置定义的操作符 &amp; , &amp;&amp; || 这些</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">·赋值（=）下标（【】）调用 （（））和成员访问操作符必须定义为成员</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">·对称的操作符一般定义为普通非成员函数</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">++ -- 一般设置为成员函数 ，因为可能改变对象状态</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">4.定义输入输出操作符</font></p> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">io操作符只能重载为非成员函数，否则做操作符只能是对象成员 用法变成了 object&lt;&lt;cin&nbsp; 不符合我们的习惯，经常把他们设置成为友元，因为可能触及私有变量。</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">输入必须加入文件结束和输入错误的错误处理</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">istream&amp;<br> operator&gt;&gt;(istream&amp; in, Sales_item&amp; s)<br> {<br>&nbsp;&nbsp;&nbsp;&nbsp; double price;<br>&nbsp;&nbsp;&nbsp;&nbsp; in &gt;&gt; s.isbn &gt;&gt; s.units_sold &gt;&gt; price;<br>&nbsp;&nbsp;&nbsp;&nbsp; // check that the inputs succeeded<br>&nbsp;&nbsp;&nbsp;&nbsp; if (in)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s.revenue = s.units_sold * price;<br>&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = Sales_item(); // input failed: reset object to default state<br>&nbsp;&nbsp;&nbsp;&nbsp; return in;<br> }</font> <p><font face="方正准圆简体" color="#0080c0" size="4">如果输入失败，调用默认构造函数恢复对象状态。</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">5.算术运算符和关系运算符</font> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">Sales_item&amp; operator -=(const Sales_item&amp; item){<br>&nbsp;&nbsp;&nbsp; units_sold-=item.units_sold;<br>&nbsp;&nbsp;&nbsp; revenue-=item.revenue;<br>&nbsp;&nbsp;&nbsp; return *this;<br>}<br>Sales_item operator - (const Sales_item&amp; lhs,const Sales_item&amp; rhs){<br>&nbsp;&nbsp;&nbsp; Sales_item res(lhs);<br>&nbsp;&nbsp;&nbsp; res+=rhs;<br>&nbsp;&nbsp;&nbsp; return res;<br>}</font> <p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p> <p><font face="方正准圆简体" color="#0080c0" size="4">一般算术运算符设置为非成员函数，与内置运算符对应，选择返回value 而不是引用。赋值运算符重载为成员函数，并用它来实现算术运算符，这样算术运算符不用friend</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">相等运算符和不等运算符一般成对出现，且用一个实现另一个</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">关系运算符 == != &gt; &lt; 一般重载成非成员函数</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">6.赋值操作符</font></p> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">必须为成员函数 （=号）</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">=和+=&nbsp; -= 一般都需要返回左操作数的引用</font></p> <p><font face="方正准圆简体" color="#0080c0" size="4">Sales_item&amp; operator = (string is){<br>&nbsp;&nbsp;&nbsp; isbn = is;<br>&nbsp;&nbsp;&nbsp; return *this;<br>}</font></p></blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">6.下标操作符</font> <blockquote> <p><font face="方正准圆简体" color="#0080c0" size="4">必须为类成员函数&nbsp;&nbsp; 返回引用使其可以在赋值操作的任意一边</font> <p><font face="方正准圆简体" color="#0080c0" size="4">一般定义一种const 返回常量引用 一种not const 引用</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     class Foo {
     public:
         int &amp;operator[] (const size_t);
         const int &amp;operator[] (const size_t) const;
         // other interface members
     private:
         vector&lt;int&gt; data;
         // other member data and private utility functions
      };</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">int&amp; Foo::operator[] (const size_t index)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data[index];&nbsp; // no range checking on index<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; const int&amp; Foo::operator[] (const size_t index) const<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data[index];&nbsp; // no range checking on index<br>&nbsp;&nbsp;&nbsp;&nbsp; }</font></p></blockquote>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">pari&lt;string,string&gt;&amp; operator[] (const&nbsp; vector&lt; pair&lt;string,string&gt;* &gt; ::size_type index){<br>&nbsp;&nbsp;&nbsp; return *wait_list.at(index);//使用at判断是否越界<br> }</font></p></blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">6.成员访问操作符</font></p>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">-&gt; 一般要求重载为成员运算符，*没有要求 ,但成员比较常见~~~</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">例子：auto-ptr~~~~</font></p>
<p><font face="方正准圆简体"><font size="4"><font color="#0080c0"><tt>ScreenPtr</tt> 的用户将会传递一个指针，该指针指向动态分配的 <tt>Screen</tt>，<tt>ScreenPtr</tt> 类将拥有该指针，并安排在指向基础对象的最后一个 <tt>ScreenPtr</tt> 消失时删除基础对象。另外，不用为 <tt>ScreenPtr</tt> 类定义默认构造函数。因此，我们知道一个 <tt>ScreenPtr</tt> 对象将总是指向一个 <tt>Screen</tt> 对象，不会有未绑定的 <tt>ScreenPtr</tt>，这一点与内置指针不同。应用程序可以使用 <tt>ScreenPtr</tt> 对象而无须首先测试它是否指向一个 <tt>Screen</tt> 对象。</font></font></font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">&nbsp;&nbsp;&nbsp;&nbsp; // private class for use by ScreenPtr only 私有类，<br>&nbsp;&nbsp;&nbsp;&nbsp; class ScrPtr {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; friend class ScreenPtr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Screen *sp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t use;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScrPtr(Screen *p): sp(p), use(1) { }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~ScrPtr() { delete sp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * smart pointer: Users pass to a pointer to a dynamically allocated Screen, which<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is automatically destroyed when the last ScreenPtr goes away<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp; class ScreenPtr {<br>&nbsp;&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; no default constructor: ScreenPtrs must be bound to an object<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScreenPtr(Screen *p): ptr(new ScrPtr(p)) { }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; copy members and increment the use count<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScreenPtr(const ScreenPtr &amp;orig):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr(orig.ptr) { ++ptr-&gt;use; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScreenPtr&amp; operator=(const ScreenPtr&amp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; if use count goes to zero, delete the ScrPtr object<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~ScreenPtr() { if (--ptr-&gt;use == 0) delete ptr; }<br>&nbsp;&nbsp;&nbsp;&nbsp; private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScrPtr *ptr;&nbsp;&nbsp;&nbsp; // points to use-counted ScrPtr class<br>&nbsp;&nbsp;&nbsp;&nbsp; }; </font>
<p><font face="方正准圆简体" color="#0080c0" size="4">指针支持的基本操作有解引用操作和箭头操作。我们的类可以这样定义这些操作：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     class ScreenPtr {
     public:
         // constructor and copy control members as before
         Screen &amp;operator*() { return *ptr-&gt;sp; }
         Screen *operator-&gt;() { return ptr-&gt;sp; }
         const Screen &amp;operator*() const { return *ptr-&gt;sp; }
         const Screen *operator-&gt;() const { return ptr-&gt;sp; }
     private:
         ScrPtr *ptr; // points to use-counted ScrPtr class
     };</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">解引用操作符是个一元操作符。在这个类中，解引用操作符定义为成员，因此没有显式形参，该操作符返回对 <tt>ScreenPtr</tt> 所指向的 <tt>Screen</tt> 的引用。</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">箭头操作符不接受显式形参。point-&gt;action();&nbsp;&nbsp; 等价于&nbsp; (point-&gt;action)();</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">可以这样使用 <tt>ScreenPtr</tt> 对象访问 <tt>Screen</tt> 对象的成员：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">ScreenPtr p(&amp;myScreen);     // copies the underlying Screen
p-&gt;display(cout);</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">因为 <tt>p</tt> 是一个 <tt>ScreenPtr</tt> 对象，<tt>p-&gt;display</tt> 的含义与对 <tt>(p.operator-&gt;())-&gt;display</tt> 求值相同。对 <tt>p.operator-&gt;()</tt> 求值将调用 <tt>ScreenPtr</tt> 类的 <tt>operator-&gt;</tt>，它返回指向 <tt>Screen</tt> 对象的指针，该指针用于获取并运行 <tt>ScreenPtr</tt> 所指对象的 <tt>display</tt> 成员。</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">重载箭头操作符必须返回指向类类型的指针，或者返回定义了自己的箭头操作符的类类型对象。</font></p></blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">6.自增自减操作符</font></p>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">一般重载为成员函数，为了与内置类型一致，前置操作符返回运算结果引用，后置操作符返回运算前的值，value not ref ，为了区分，后置操作符提供了一个实参0；</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">// prefix: return reference to incremented/decremented object<br>&nbsp;&nbsp;&nbsp; CheckedPtr&amp; CheckedPtr::operator++()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (curr == end)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw out_of_range<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("increment past the end of CheckedPtr");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++curr;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // advance current state<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return *this;<br>&nbsp;&nbsp;&nbsp; }</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">CheckedPtr CheckedPtr::operator++(int)<br>&nbsp;&nbsp;&nbsp;&nbsp; { </font>
<p><font face="方正准圆简体" color="#0080c0" size="4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // no check needed here, the call to prefix increment will do the check<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CheckedPtr ret(*this);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // save current value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++*this;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // advance one element, checking the increment 用前置实现它，不用判断出界了<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // return saved state<br>&nbsp;&nbsp;&nbsp;&nbsp; }</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">显式调用：</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">CheckedPtr parr(ia, ia + size);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // iapoints to an array of ints<br>parr.operator++(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // call postfix operator++<br>parr.operator++();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // call prefix operator++ </font></p></blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">7 调用操作符和函数对象</font></p>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">struct absInt {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int operator() (int val) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return val &lt; 0 ? -val : val;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp; }; </font>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4">通过为类类型的对象提供一个实参表而使用调用操作符，所用的方式看起来像一个函数调用： </font>
<p><font face="方正准圆简体" color="#0080c0" size="4">&nbsp;&nbsp;&nbsp;&nbsp; int i = -42;<br>&nbsp;&nbsp;&nbsp;&nbsp; absInt absObj;&nbsp; // object that defines function call operator<br>&nbsp;&nbsp;&nbsp;&nbsp; unsigned int ui = absObj(i);&nbsp;&nbsp;&nbsp;&nbsp; // calls absInt::operator(int) </font>
<p><font face="方正准圆简体" color="#0080c0" size="4">函数调用操作符必须声明为成员函数。一个类可以定义函数调用操作符的多个版本，由形参的数目或类型加以区别。</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">定义了调用操作符的类，其对象常称为函数对象，即它们是行为类似函数的对象。</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">函数：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     // determine whether a length of a given word is 6 or more
     bool GT6(const string &amp;s)
     {
         return s.size() &gt;= 6;
     }
</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">函数对象：</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">// determine whether a length of a given word is longer than a stored bound<br>&nbsp;&nbsp;&nbsp;&nbsp; class GT_cls {<br>&nbsp;&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GT_cls(size_t val = 0): bound(val) { }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool operator()(const string &amp;s)<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;&nbsp;&nbsp;&nbsp; { return s.size() &gt;= bound; }<br>&nbsp;&nbsp;&nbsp;&nbsp; private:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::string::size_type bound;<br>&nbsp;&nbsp;&nbsp;&nbsp; };</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">for (size_t i = 0; i != 11; ++i)<br>&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; count_if(words.begin(), words.end(), GT(i))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; " words " &lt;&lt; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; " characters or longer" &lt;&lt; endl;</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">函数对象的便捷性】</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plus&lt;int&gt; intAdd;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // function object that can add two int values<br>&nbsp;&nbsp;&nbsp;&nbsp; negate&lt;int&gt; intNegate;&nbsp;&nbsp; //&nbsp; function object that can negate an int value<br>&nbsp;&nbsp;&nbsp;&nbsp; // uses intAdd::operator(int, int) to add 10 and 20<br>&nbsp;&nbsp;&nbsp;&nbsp; int sum = intAdd(10, 20);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // sum = 30<br>&nbsp;&nbsp;&nbsp;&nbsp; // uses intNegate::operator(int) to generate -10 as second parameter<br>&nbsp;&nbsp;&nbsp;&nbsp; // to intAdd::operator(int, int)<br>&nbsp;&nbsp;&nbsp;&nbsp; sum = intAdd(10, intNegate(10));&nbsp;&nbsp;&nbsp; // sum = 0</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">函数适配器：</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">banding器，它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象</font>
<p><font face="方正准圆简体"><font size="4"><font color="#0080c0">求反器是一种函数适配器，它将谓词函数对象的真值求反。标准库定义了两个求反器：<tt>not1</tt> 和 <tt>not2 分别求反一元二元对象</tt></font></font></font></p></blockquote>
<p><tt><font face="方正准圆简体" color="#0080c0" size="4">8。实参匹配和转换（俺来看重载操作符的原因啊，，，）</font></tt>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">转换操作符是一种特殊的类成员函数。它定义将类类型值转变为其他类型值的转换。转换操作符在类定义体内声明，在保留字 <tt>operator</tt> 之后跟着转换的目标类型：</font></p></blockquote>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">转换函数采用如下通用形式：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     operator type();
</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">转换函数必须是成员函数，不能指定返回类型，并且形参表必须为空。</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">虽然转换函数不能指定返回类型，但是每个转换函数必须显式返回一个指定类型的值。例如，<tt>operator int</tt> 返回一个 <tt>int</tt> 值；如果定义 <tt>operator Sales_item</tt>，它将返回一个 <tt>Sales_item</tt> 对象，诸如此类。</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">转换函数一般不应该改变被转换的对象。因此，转换操作符通常应定义为 <tt>const</tt> 成员。</font></p>
<p><font face="方正准圆简体" color="#0080c0" size="4">只要存在转换，编译器将在可以使用内置转换的地方自动调用它</font></p>
<li>
<p><font face="方正准圆简体" color="#0080c0" size="4">In expressions:</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">在表达式中：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     SmallInt si;
     double dval;
     si &gt;= dval          // si converted to int and then convert to double</font></pre>
<li>
<p><font face="方正准圆简体" color="#0080c0" size="4">In conditions:</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">在条件中：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     if (si)                // si converted to int and then convert to bool</font></pre>
<li>
<p><font face="方正准圆简体" color="#0080c0" size="4">When passing arguments to or returning values from a function:</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">将实参传给函数或从函数返回值：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     int calc(int);
     SmallInt si;
     int i = calc(si);      // convert si to int and call calc</font></pre>
<li>
<p><font face="方正准圆简体" color="#0080c0" size="4">As operands to overloaded operators:</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">作为重载操作符的操作数：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     // convert si to int then call opeator&lt;&lt; on the int value
     cout &lt;&lt; si &lt;&lt; endl;</font></pre>
<li><a name="idd1e109936"></a><a name="idd1e109941"></a>
<p><font face="方正准圆简体" color="#0080c0" size="4">In an explicit cast:</font>
<p><font face="方正准圆简体" color="#0080c0" size="4">在显式类型转换中：</font><pre><font face="方正准圆简体" color="#0080c0" size="4">     int ival;
     SmallInt si = 3.541; //
     instruct compiler to cast si to int
     ival = static_cast&lt;int&gt;(si) + 3;
</font></pre>
<p><font face="方正准圆简体" color="#0080c0" size="4">类类型转换之后不能再跟另一个类类型转换。如果需要多个类类型转换，则代码将出错。（指的是不能连续两个自定义的类型转换，但是内置类型转换可以的）</font></p></li></blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font></p>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4">还有一部分是实参匹配和转换 ，没时间了 以后再看~~~~ </font></p></blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font>&nbsp;</p>
<blockquote>
<p><font face="方正准圆简体" color="#0080c0" size="4"></font></p></blockquote><img src ="http://www.cppblog.com/zqsand/aggbug/109748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-15 16:40 <a href="http://www.cppblog.com/zqsand/archive/2010/03/15/109748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>素数筛法</title><link>http://www.cppblog.com/zqsand/archive/2010/03/12/109528.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Fri, 12 Mar 2010 06:04:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/12/109528.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/109528.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/12/109528.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/109528.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/109528.html</trackback:ping><description><![CDATA[<p></p><pre class="code"><span style="background: #373737; color: #d24400">#include </span><span style="background: #373737; color: #ffc4e1">&lt;iostream&gt; 
</span><span style="background: #373737; color: #d24400">#include </span><span style="background: #373737; color: #ffc4e1">&lt;vector&gt;
</span><span style="background: #373737; color: #d24400">#include </span><span style="background: #373737; color: #ffc4e1">"time.h"
</span><span style="background: #373737; color: #d24400">using namespace </span><span style="background: #373737; color: #c1c0c1">std</span><span style="background: #373737; color: silver">; 
</span><span style="background: #373737; color: #d24400">void </span><span style="background: #373737; color: #c1c0c1">sieve</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">){
    </span><span style="background: #373737; color: #c1c0c1">vector</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #d24400">bool</span><span style="background: #373737; color: silver">&gt; </span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">,</span><span style="background: #373737; color: #d24400">true</span><span style="background: #373737; color: silver">);
    </span><span style="background: #373737; color: #c1c0c1">vector</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #d24400">int</span><span style="background: #373737; color: silver">&gt; </span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">;
    </span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">cnt</span><span style="background: #373737; color: silver">=</span><span style="background: #373737; color: #9ab40a">0</span><span style="background: #373737; color: silver">;
    </span><span style="background: #373737; color: #d24400">for</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">=</span><span style="background: #373737; color: #9ab40a">2</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">++){
        </span><span style="background: #373737; color: #d24400">if</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">])</span><span style="background: #373737; color: #c1c0c1">cnt</span><span style="background: #373737; color: silver">++,</span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">.</span><span style="background: #373737; color: #c1c0c1">push_back</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">);
        </span><span style="background: #373737; color: #d24400">for</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">=</span><span style="background: #373737; color: #9ab40a">0</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #c1c0c1">cnt</span><span style="background: #373737; color: silver">&amp;&amp;</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">*</span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">]&lt;</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">++){
            </span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">*</span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">]]=</span><span style="background: #373737; color: #d24400">false</span><span style="background: #373737; color: silver">;
            </span><span style="background: #373737; color: #d24400">if</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">%</span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">t</span><span style="background: #373737; color: silver">]==</span><span style="background: #373737; color: #9ab40a">0</span><span style="background: #373737; color: silver">)</span><span style="background: #373737; color: #d24400">break</span><span style="background: #373737; color: silver">;
        }
    }
    </span><span style="background: #373737; color: #00e300">/*for(int i=0;i&lt;cnt;i++)
        cout&lt;&lt;prime[i]&lt;&lt;" ";*/
</span><span style="background: #373737; color: silver">}
</span><span style="background: #373737; color: #d24400">void </span><span style="background: #373737; color: #c1c0c1">oldseive</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">){
    </span><span style="background: #373737; color: #c1c0c1">vector</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #d24400">bool</span><span style="background: #373737; color: silver">&gt; </span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">,</span><span style="background: #373737; color: #d24400">true</span><span style="background: #373737; color: silver">);
    </span><span style="background: #373737; color: #c1c0c1">vector</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #d24400">int</span><span style="background: #373737; color: silver">&gt; </span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">;
    </span><span style="background: #373737; color: #d24400">for</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">=</span><span style="background: #373737; color: #9ab40a">2</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">++){
        </span><span style="background: #373737; color: #d24400">if</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">]){
            </span><span style="background: #373737; color: #c1c0c1">prime</span><span style="background: #373737; color: silver">.</span><span style="background: #373737; color: #c1c0c1">push_back</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">);
            </span><span style="background: #373737; color: #d24400">for</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">j</span><span style="background: #373737; color: silver">=</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">*</span><span style="background: #373737; color: #9ab40a">2</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">j</span><span style="background: #373737; color: silver">&lt;</span><span style="background: #373737; color: #c1c0c1">n</span><span style="background: #373737; color: silver">;</span><span style="background: #373737; color: #c1c0c1">j</span><span style="background: #373737; color: silver">+=</span><span style="background: #373737; color: #c1c0c1">i</span><span style="background: #373737; color: silver">)
                </span><span style="background: #373737; color: #c1c0c1">isprime</span><span style="background: #373737; color: silver">[</span><span style="background: #373737; color: #c1c0c1">j</span><span style="background: #373737; color: silver">]=</span><span style="background: #373737; color: #d24400">false</span><span style="background: #373737; color: silver">;
        }
    }
    </span><span style="background: #373737; color: #00e300">/*for(int i=0;i&lt;prime.size();i++)
        cout&lt;&lt;prime[i]&lt;&lt;" ";*/
</span><span style="background: #373737; color: silver">}
</span><span style="background: #373737; color: #d24400">int </span><span style="background: #373737; color: #c1c0c1">main</span><span style="background: #373737; color: silver">(){
    </span><span style="background: #373737; color: #c1c0c1">clock_t start</span><span style="background: #373737; color: silver">,</span><span style="background: #373737; color: #c1c0c1">end</span><span style="background: #373737; color: silver">;
    </span><span style="background: #373737; color: #c1c0c1">start </span><span style="background: #373737; color: silver">= </span><span style="background: #373737; color: #c1c0c1">clock</span><span style="background: #373737; color: silver">();
     </span><span style="background: #373737; color: #c1c0c1">sieve</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #9ab40a">2000000</span><span style="background: #373737; color: silver">);
     </span><span style="background: #373737; color: #00e300">//oldseive(2000000);
    </span><span style="background: #373737; color: #c1c0c1">end  </span><span style="background: #373737; color: silver">= </span><span style="background: #373737; color: #c1c0c1">clock</span><span style="background: #373737; color: silver">();
    </span><span style="background: #373737; color: #d24400">double </span><span style="background: #373737; color: #c1c0c1">time </span><span style="background: #373737; color: silver">= </span><span style="background: #373737; color: #d24400">double</span><span style="background: #373737; color: silver">(</span><span style="background: #373737; color: #c1c0c1">end</span><span style="background: #373737; color: silver">-</span><span style="background: #373737; color: #c1c0c1">start</span><span style="background: #373737; color: silver">)/</span><span style="background: #373737; color: #c1c0c1">CLOCKS_PER_SEC</span><span style="background: #373737; color: silver">;
    </span><span style="background: #373737; color: #c1c0c1">cout</span><span style="background: #373737; color: silver">&lt;&lt;</span><span style="background: #373737; color: #c1c0c1">endl</span><span style="background: #373737; color: silver">&lt;&lt; </span><span style="background: #373737; color: #c1c0c1">time</span><span style="background: #373737; color: silver">&lt;&lt;</span><span style="background: #373737; color: #c1c0c1">endl</span><span style="background: #373737; color: silver">;
} </span></pre>
<p>线性筛法sieve 1.546s oldsieve 2.875s 快了将近一倍</p>
<p>old sieve 缺陷：合数可能被多次筛掉，例如 30被2，3，5筛掉了3次 然后 线性筛法限定了 任何一个合数只被它的最小质因数筛掉一次，怎么做到这一点~~</p>
<p>if(i%prime[t]==0) break; 如果此时筛掉的合数从小到大找到第一个可以整除的质数，那么显然他找到了它的最小质因数，此时我们停止搜索质数表，因为后面的质数比当前的prime[t]要大，如果我们用prime[t+n]*i 筛掉了一个合数，这个合数必然可以表述成为 prime[t]*someK&nbsp; *prime[t+n] 也就是说这个合数的最小质因数也是prime[t],他应该被 prime[t]筛掉--&gt;当程序运行到 someK*prime[t+n] 的时候~~~~</p>
<p>over--------------------------------------------------------------------</p><img src ="http://www.cppblog.com/zqsand/aggbug/109528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-12 14:04 <a href="http://www.cppblog.com/zqsand/archive/2010/03/12/109528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探索C++对象模型读书笔记 (四)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/09/109322.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Tue, 09 Mar 2010 14:20:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/09/109322.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/109322.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/09/109322.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/109322.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/109322.html</trackback:ping><description><![CDATA[<p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Function 语义学</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">····member 的各种调用方式~</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">1.非静态成员函数·</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">float Point3d::mangitude3d()const{…}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">会变成 float Point3d::magnitude(const Point3d* this){…}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">c++的准则之一：非静态成员函数至少必须同一般的nonmember function 有相同的效率</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">名称的特殊处理：（name mangling）一般member名称前面都会加上class名称，形成独一无二的命名，class Bar {public ：int ival；} 可能变成 ival_3Bar ;3应该是bar的长度了。</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">这样可以防止继承体系中两个类定义同样名字的变量~</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果使用extern “C” 就可以压制nonmember 的mangling 效果</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">2.虚拟成员函数·</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果normalize 是虚拟函数 他会被翻译成:</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">(*ptr-&gt;vptr[1])(ptr); 第二个ptr是this指针</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">类似的magnitude 会变成</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">(*this-&gt;vptr[2])(this);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">而magnitude是在normalize之后调用的因此此时已经确定this指向的是Point3d 因此可以直接调用Point3d::magnitude()更有效率 </font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果用一个对象调用一个虚拟函数应该把它当做正常函数来对待，因为可以确定对象类型直接调用相应的函数即可，在这种情况下，虚拟函数也可以inline 来提高效率了~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">3.静态成员函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">class A{<br>public:<br>&nbsp;&nbsp;&nbsp; static int a;<br>&nbsp;&nbsp;&nbsp; static int geta(){return a;} <br>};<br>int A::a=33333;<br>int main(){ <br>&nbsp;&nbsp;&nbsp; cout&lt;&lt; ((A*)0)-&gt;geta()&lt;&lt;endl;<br>} </font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">static的主要特征是他没有this 指针，这样导致“</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">他不能直接存取其class中的nonstatic members</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">他不能被声明为const volatile 或者virtual</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">他不需要经由class object 才被调用 虽然大部分情况是这样调用的</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果取一个static member func 地址则得到的是他在内存中的真正地址，而且得到的是一个函数指针，而不是一个指向class member 函数的指针</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">····虚拟成员函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">为了支持virtual func 机制，必须首先能够对多态对象由某种形式的运行期类型判断方法</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">c++中多态表示：以一个public blase class 指针或者引用 寻址出一个derived class object 的意思</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">识别出哪个类需要支持多态只要看他是否有任何的virtual func </font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">~~~单一继承</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">vtable中每一个virtual func（包括pure func）都被指派一个固定的索引值，这个索引在整个继承体系中保持与特定的virtual function 的关联</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">当一个class 继承自上一个class时候</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">1.可以继承base class 声明的virtual func ，这样该函数实体的地址会被拷贝到他的vtable相对应的slot 中，位置x不变 这样调用时候 ptr-&gt;func();会翻译成 (*ptr-&gt;vtbl[x])func(ptr) ;而不用管ptr 到底是一个base 还是一个derived</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">2.他可以使用自己的函数实体，表示他自己的函数地址必须放在相应的位置x处 ,跟上面的例子一样</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">3.可以加入新的virtual 函数，这时候vtbl 会变大</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">~~~多重继承呢</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">多重继承时候 例如 Derived public 自 Base1,Base2</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Base2 *pbase2 = new Derived; 新的Derived必须调整</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Base2 *pbase2 = tmp?tmp+sizeof(Base1):0;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">当程序员删除pbase2指向的对象时指针必须再一次调整。上述的调整并不能在编译时期设定，因为pbase2指向的对象只有在执行期才能确定。</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">同样道理，pbase2 如果要调用函数的话，调用操作会引发必要的指针调整，也必须在执行期调整。</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Bjarne采用扩充vtable 每一项记录调整this指针的信息，但浪费，因为大部分不需要调整</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Thunk技术是用一段汇编实现调整this指针以及跳到virtual func的过程</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">调整this指针的第二个负担是：如果由derved class 调用，或者由第二个base class 调用，同一个函数可能在virtual table 对应多个slots</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">pbase1 和derived 的vtable可以合并，他们用同样的slots 偏移，里面可以放真正的地址，而pbase2 需要调整this指针，其vtabl 相应的地址放的是相应的thunk地址。</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">可以看到”：</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">1.如果通过指向第二个base class 指针调用derived的func ptr 需要调整</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">2.如果通过指向derived指针调用从第二个继承来的func 需调整</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">3.如果允许virtual func 返回类型有所变化，可能base 可能derived，也需要调整this</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Microsoft 用address point 策略，即将用来改写别人的函数，期待获得的参数（this）是引入该class 的地址，这就是函数的address class（~~不了啊~~）</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">~~~虚拟继承下的virtual func</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp; 即便只有一个base clas 它的布局转换也需要this 指针的调整，相当复杂~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">…指向成员函数的指针</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">double Point::x();</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">可以定义指向成员函数的指针</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">double (Point::* pmf)()=&amp;Point::x;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">调用可以&nbsp; (origin.*pmf)() 或者 ptr-&gt;*pmf();</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果是虚拟函数的指针呢？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Point* ptr= new Point3d;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果x是一个虚拟函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">(ptr-&gt;*pmf)();仍然是Point3d::x()被调用么？</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">答案~~是的</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">因为取得虚拟函数的地址其实取得的是虚拟函数的offset值</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">调用会变成&nbsp; (*ptr-&gt;vtbl[(int)pmf])(ptr);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">class A{<br>public:<br>&nbsp;&nbsp;&nbsp; static int a;<br>&nbsp;&nbsp;&nbsp; static int geta()&nbsp; {return a;}&nbsp; //静态并不能作为重载条件<br>&nbsp;&nbsp;&nbsp; int geta(int x){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return a;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp; geta( int&nbsp; a)const{} // const成员函数 ，可以作为重载条件<br>};<br>int A::a=33333;<br>int main(){ <br>&nbsp;&nbsp;&nbsp; A a;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt; ((A*)0)-&gt;geta()&lt;&lt;endl;//静态成员函数的一种调用方法 ((A*)0)-&gt;geta()<br>&nbsp;&nbsp;&nbsp; int(*p)()= &amp;A::geta;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;(*p)()&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; int (A::* pgeta)(int a) = &amp;A::geta;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;(a.*pgeta)(3)&lt;&lt;endl;<br>} </font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">输出均为33333&nbsp; </font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">多重继承下呢？？？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">Microsoft提供了3种解决方法：</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">一种：单一继承的情况（带vcall thunk地址或者函数地址）</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">2多重继承 带有faddr 和delta</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">虚拟继承 带有四个members</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">（·····具体以后再查吧）</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">----------</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">inline members</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">真正的inline 函数扩展是在调用的那一个点上，这回带来参数的求值操作以及暂时性对象的管理</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">形式参数 formal arguments</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">在inline 期间 每一个形式参数都会被相应的实际参数取代，副作用是，不可以只是简单的一一封塞程序中出现的每一个形式参数，因为这将导致对于实际参数的多次求值操作，可能产生 带来副作用的 实际参数，通常这需要嵌入实际对象的~~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">所以，如果实际参数是常量，那么我们可以直接绑定，如果不是常量也没有副作用，我们直接代替，否则~~~暂时对象会需要的~·</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">例如：</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">inline int min(int i,int j) { return i&lt;j ? i:j ;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">minval = min(val1,val2);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">minval = min(11,12);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">minval = min (foo(),bar()+1);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">这会扩展成: minval = val1&lt;val2 ? val1?val2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">minval = 11;( 常量哦)</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">int t1,t2; minval =(t1 = foo()), (t2=bar()+1),t1&lt;t2?t1:t2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如果我们改变函数定义</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">{int minval = i&lt;j?i:j; return minval;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">如下调用{int minval ; minval = min(val1,val2);}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">为了维护局部变量可能会变成：</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">{ int m_lv_minval; minval=(__min_lv_minval=val1&lt;val2?val1:val2),min_lv_minval;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">一般而言，inline 函数的每一个局部变量都必须放在函数调用的一个封闭区段中，拥有一个独一无二的名字，如果inline函数以单一表达式扩展多次，那么每次扩展都需要自己的一组局部变量。如果inline 函数可以以分离的多个式子被扩展多次，那么只需要一组局部变量就可以重复使用，因为他们被封闭在自己的scope中：</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">例如 minval = min(val1,val2) + min(foo(),foo()+1) ;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">扩展 int __min_lv_minval_0,__min_lv_minval_1,t1,t2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">minval = ((__min_lv_minval_0 = val1&lt;val2?val1:val2),__min_lv_minval_0)+…);</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">参数带有副作用或者是以一个单一表达式做多重调用，或者是在inline 函数内部有多个局部变量</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">都会产生局部变量，要小心对待</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">--------------------结束线哦~~~~~~··----------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#7d9cec" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/109322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-09 22:20 <a href="http://www.cppblog.com/zqsand/archive/2010/03/09/109322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探索C++对象模型读书笔记 (三)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/07/109118.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sun, 07 Mar 2010 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/07/109118.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/109118.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/07/109118.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/109118.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/109118.html</trackback:ping><description><![CDATA[<p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">DATA 语义学</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">这段代码输出什么？</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">#include &lt;iostream&gt;<br>using namespace std;<br>class A{ public:A(){ac='s';}private:char ac;};<br>class B:virtual public A{public:B(){a='e';}char a; };<br>class C:virtual public A{ }; <br>class D:public&nbsp; B,public&nbsp; C<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; D():A(),B(),C(){b=13;}<br>&nbsp;&nbsp;&nbsp; int b;<br>};<br>int main(){<br>&nbsp;&nbsp;&nbsp; D d;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"sizeof(A)="&lt;&lt;sizeof(A)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"sizeof(B)="&lt;&lt;sizeof(B)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"sizeof(C)="&lt;&lt;sizeof(C)&lt;&lt;endl; <br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"sizeof(D)="&lt;&lt;sizeof(D)&lt;&lt;endl; <br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of A's subobject in d"&lt;&lt;(A*)&amp;d&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of B's subobject in d"&lt;&lt;(B*)&amp;d&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of C's subobject in d"&lt;&lt;(C*)&amp;d&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of D's subobject in d"&lt;&lt;(D*)&amp;d&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;endl; <br>&nbsp;&nbsp;&nbsp; int* p = (int*)(*((int*)&amp;d));<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of b's virtual base table="&lt;&lt;p&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"first member in b's virtual base table="&lt;&lt;*p&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"second member in b's virtual base table="&lt;&lt;*(p+1)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"third member in b's virtual base table="&lt;&lt;*(p+2)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;endl;&nbsp; <br>&nbsp;&nbsp;&nbsp; p= (int*)*((int*)((C*)&amp;d));<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"address of c's virtual base class table= "&lt;&lt;p&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"first member in c's virtual base table="&lt;&lt; *p&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"second member in c's virtual base table="&lt;&lt;*(p+1)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;"third member in c's virtual base table="&lt;&lt;*(p+2)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; char *pchar= (char*)(&amp;d)+4; //char型加4&nbsp;&nbsp; 注意A中的ac其实是私有变量，B不应该可以访问到的，实际上通过强制转换可以非法触及她-。-<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;*pchar&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;*(pchar+12)&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; B b;<br>&nbsp;&nbsp;&nbsp; int *pint =(int*)(&amp;b)+1; //int型+1&nbsp; <br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;*((char*)(pint))&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp; pint = (int*)(&amp;d)+3;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;*(pint)&lt;&lt;endl;<br>} </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">结果是：</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">sizeof(A)=1<br>sizeof(B)=9<br>sizeof(C)=5<br>sizeof(D)=17 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">address of A's subobject in d0012FF74<br>address of B's subobject in d0012FF64<br>address of C's subobject in d0012FF6C<br>address of D's subobject in d0012FF64 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">address of b's virtual base table=00403350<br>first member in b's virtual base table=0<br>second member in b's virtual base table=16<br>third member in b's virtual base table=0 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">address of c's virtual base class table= 00403358<br>first member in c's virtual base table=0<br>second member in c's virtual base table=8<br>third member in c's virtual base table=0<br>e<br>s<br>e<br>13 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp; </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">1.语言本身造成的负担：如virtual baseclass</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">2.对齐造成的负担（对齐会单独开题讨论）</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">3.编译器优化处理 A虽然是空的 but 为了让A的两个object在内存中得到不同的地址，编译器给他加上了一个byte，但是B和C都没有这一个byte呢？这是编译器做了优化，允许省掉这一个byte</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">看上面的代码”：</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">环境是vs2008 对齐设置为4字节</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">A的大小为1 因为有一个char 没有对齐因为不是结构型对象，如果A没有这个char大小依然是1的</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">B的大小为9 首先开始是它的virtual base class ptr，4个字节的指针，然后是他自己的member 1个char 此时为了保证其对象完整性编译器对齐到4字节处也就是在第九个字节内放入基类的member</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">这样如果我们把A=B B赋给A，传输可以从整4字节开始割出A即可</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">C的大小是5 没什么好解释</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">D的大小是17首先是B的8字节(4字节vbptr+1字节char member+3字节对齐)然后是C的4字节vbptr,然后是自己的member4字节最后是1字节的base class member,可以看到B和C的base class table中的项都是自己位置与这个member的offset 值</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">不同编译器可能结果不同的，因为c++ standard 并没有强制规定 base class subobjects的顺序等</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">data member 是程序执行过程中的某种状态：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">static data member 是整个class 的状态</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">non-static data member 是个别class-object 的状态</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">c++对象尽量以空间优化和存取速度的考虑来表现non-static members ，并且和c的struct 数据配置的兼容性。</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">static data member 放在程序的一个global data segment 中，不会影响个别的class-object 大小</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">，在class没有object 时已经存在，但是template中有些不同</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">-----DATA member 的绑定</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">始终把nested type 声明 放在class 起始处，argument list 中的名称会在第一次遇到时候被适当的决议完成，因此extern 和nested type names 之间的非直觉绑定操作还是会发生。</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">---- DATA 的存取</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">Point3d origin,*pt=&amp;origin;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">origin.x = 0.0; 和 pt-&gt;x=0.0 ; 有什么区别么？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">如果x是静态data member 则完全没有区别 因为他们都在data segment 中和object无关</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">~nonstatic data member---------</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">如果point3d不包含虚拟继承那么没有差异</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">否则我们不能确定pt中必然指向哪一种因此不能在编译器确定offset需要一些运行时候的计算抉择，而origin则不同一定是某一个类型的所以没有问题</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">多继承或者单继承都不会带来访问上的影响，因为他们都可以向c的结构体那样在编译时期确定各个member的offset。即使是多继承pt指向第二个baseclass的data，由于member的位置在编译时期就已经固定了，因此存取member只是一个offset运算，像单一继承那样简单，不管是指针，reference或者object都一样 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">只有virtual base class 会带来一些损耗，因为他使得对象模型变得复杂了</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">如果我们在一个类中加入了virtual func 会发生什么~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">1. 会产生一个virtual table，存放每一个virtual func地址以及rtti支持的type_info</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">2.class object 内都加入一个vptr，提供执行期的链接</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">3.加强ctor 设定vpr初值</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">4.加强dtor 消除vptr 从dirived class 到 base class</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">虚拟继承：</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">他必须支持某种形式的“shared subobject”继承</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">那么一个object会分成一个不变局部和一个共享局部的数据，共享局部就是virtual base class subobject，他的位置会因为每次派生操作发生变化(例如一个virtual base class subobject的位置在不同级别的继承体系中的位置是不确定的，不像多继承单继承那样有固定的offset)，所以他只能间接存取，因此产生了效率缺损.(间接是指的是他只能首先读出他的指针，然后根据指针的内容取到他)</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">所以在虚拟继承基类中最好不要有data member</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">-------指向DATAmember 的指针</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">#include &lt;iostream&gt;<br>using namespace std; <br></font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">class&nbsp; A<br>{<br>public: </font> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;&nbsp;&nbsp; int a;<br>};<br>int main(){ <br>&nbsp;&nbsp;&nbsp; int&nbsp; A::* p=&amp;A::a;<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;p&lt;&lt;endl; <br>}</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">输出 1</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">因为为了防止&amp;A::a和 int A::*a = 0；一样把他加了1。 </font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">虚拟继承带来的主要冲击是，妨碍了优化的有效性，因为每一层虚拟继承都带来了一个额外层次的间接性，在编译器中存取 类似point::x的操作pb.*bx</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">会被转化为 &amp;pb-&gt;vbcPoint+bx</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">而不是转换成 &amp;pB +bx</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">额外的间接性会降低“把所有操作都搬移到缓存器中执行”优化能力，也就是降低了局部性~</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3"></font></p> <p><font face="YaHei Consolas Hybrid" color="#b4d1fe" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/109118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-07 16:39 <a href="http://www.cppblog.com/zqsand/archive/2010/03/07/109118.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探索C++对象模型读书笔记 (二)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/03/108832.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Wed, 03 Mar 2010 14:23:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/03/108832.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/108832.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/03/108832.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/108832.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/108832.html</trackback:ping><description><![CDATA[<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">构造函数语义学</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">--了解编译器在构造对象时背着我们干了什么勾当</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Default Ctor 在需要的时候被构建出来~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">什么需要? 是编译器需要而不是程序的需要,所以不要期望编译器生成的Ctor会帮我们把我们的成员变量初始化为零。那是程序的需要，也就是我们程序员的任务····</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">例如：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class Foo(public:int val;);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void foo_bar(){Foo bar; if(bar.val)dosth;} 不要期望编译器帮我们初始化它为0。只有global变量会初始化为0，初始化val这样的变量需要我们自己写代码的~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Default Ctor分为trival（没用的）和non-trival的，下面讨论什么时候编译器需要ctor 也就是有用的ctor，这时候如果我们没有提供一个默认的default ctor 它会帮我们合成一个的~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">1.带有Default Ctor 的member class object</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">很好理解，既然内部成员含有default ctor 那么我们创建新的对象时需要调用它，而我们并木有调用它的函数，编译器自然会帮我们提供一个。如果我们提供了default ctor ，那么编译器会在我们提供的函数加入调用必须调用的member class 的default ctor。同样的在每一个ctor里面都将在用户写的代码之前调用需要调用的default ctor -------看例子：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">class Dopey();class Sneezy{public:Sneezy(int val);Sneezy();};class Bashful{public:BashFul();};</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">class Snow_white{public: Dopey dopey;Sneezy sneezy;Bashful bashful;private:int muble};</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如果Snow_white没有定义default ctor 那么编译器会创建一个，并在其中依照声明顺序依次调用dopey sneezy bashful的default ctor 然而如果：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Snow_white::Snow_white():sneezy(1024){muble=2045;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">编译器会扩张为</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Snow_white::Snow_white():sneezy(1024){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; dopey.Dopey::Dopey();</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; sneezy.Sneezy::Sneezy(1024);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; bashful.Bashful::Bashful();</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; /////////&nbsp;&nbsp; explicit user code</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; muble = 2048;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">} </font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">2.派生自带有Default ctor 的 base class</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">同样道理如果父类有Default ctor 子类当然要调用，编译器会为想上面一样为我们加上</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">3.含有virtual functions的Class</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">创建object 时候需要ctor 来设置好vptr</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">4.带有virtual base class </font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">virtual base 实现方法各有不同，然而共同点是必须是virtual base class 在其每一个derived class中的位置能够与执行期准备妥当 </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X A B C 菱形继承</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">void foo(const A*pa){pa-&gt;i=1024;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">foo(new A);foo(new C);</font></p></blockquote> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"> 知道pa 后 i在对象中的位置并不是固定的，而是在运行时真正确定pa指向什么对象A还是C才能确定的，因此需要设定一个指向基类subobject的指针，所以需要ctor工作了</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">OK:</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">1.任何class 如果没有定义Default ctor 就会被合成一个</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">2.合成出来的Default ctor 会明确设定每一个data member值</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">错的很easy了~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">-------------------------------------------------------------------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">再来看 Copy Ctor：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">copy ctor 负责用另一个对象初始化一个对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">operator = 负责用另一个对象给一个对象赋值</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">直接赋值时，传参时，返回时可能调用Copy ctor </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Default member initialization~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">也就是memberwise 的initialization</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">他会把每一个data member （内建的或者派生的）从一个object 拷贝到另一个object中去</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如果object允许bitwise的拷贝那么编译器就不用生成一个nontrival的default copy ctor</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">什么时候不可以呢~</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">1 内含一个member object 而后者含有copy constructor (声明或者合成的)</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">2&nbsp; 继承一个base class 后者有copy ctor</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">3&nbsp; 含有virtual func</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">4&nbsp; 派生自一个继承链，其中有virtual base class</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">1和2 中编译器会把member 或者baseclass copy ctor 调用安插在合成的copy ctor 中</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">3 中：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如果两个同样类型的object赋值时，没有问题因为他们的vptr相同</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">但是考虑子类赋值给父类，此时vptr需要更改，那么此时不具有bitwise特性，因此需要编译器来加入语句正确更新vptr</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">4中：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">每个编译器都承诺必须让derived class 中的virtual base class object 在执行期间准备妥当，维护位置完整性是编译器的责任。bitwise copy 有可能会破坏这个位置所以编译器需要在自己合成的copy ctor 中作出仲裁</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">同样问题发生在继承体系中子类向父类赋值时，由于对象模型问题，直接bitwise复制可能会导致base class object 的破坏（后面章节会有讨论）</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">--------------------------------------------------------------------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">程序转化语义学:</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X x0;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">void foo(){X x1(x0); X x2=x0; X x3=X(x0);}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">转化：重写定义，初始化操作会被剥除&nbsp;&nbsp; copy constructor 调用会被安插</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">void foo(){ X x1;X x2; X x3;&nbsp; x1.X::X(x0); x2.X::X(x0); x3.X::X(x0);}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">参数的初始化：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">一种策略导入暂时的object</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">void foo(X x0);X xx; foo(xx);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">转化：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X _tmp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">_tmp.X::X(x0); foo(_tmp);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">foo变成 void foo(X&amp; x0);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">另一种是拷贝构建：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">把实际参数直接建构造应该在的位置上，函数返回时局部对象的destructor 会执行</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">也就是说把x0建构在foo 的函数执行的地方</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">返回值的初始化：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X bar(){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; X xx;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; return xx;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">返回值如何从局部对象xx拷贝而来呢？</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">一种方法：1.加上额外参数，类型是class object的reference，这个参数用来放置被拷贝建构的返回值 （注意拷贝建构也就是说他被放在应该在的位置，也就是说不是局部变量了）</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">2.return 指令之前安插一个copy constructor 调用操作 ，以便将传回的object 内容当做上述参数的初值</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">so 上面的程序变成了：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">void bar(X&amp; _result){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; X xx;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; xx.X::X(); //编译器产生的default ctor 调用</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; _result.X::X(xx);//编译器产生的copy ctor 调用</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp; return ;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">现在编译器必须转换bar的调用操作 X xx=bar();转换成 X xx; bar(xx); // 注意不用copy ctor了直接操作在xx上了 如果编译器做了优化 这就是named return value 优化</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">而：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">bar.memfunc();//bar()传回的X 调用成员函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">变成：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X _tmp;&nbsp; (bar(_tmp),_tmp).memfunc();</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">同样道理函数指针 X(*pf)(); 变成 void (*pf)(X&amp;);</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">使用者的优化:</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X bar(const T&amp; y,const T&amp; z){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; X xx; </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; 通过 y z 计算xx</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp; return xx;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">这种情况下要iuxx被memberwise拷贝到编译器产生的_result中，</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如果定义 ctor来利用yz计算xx则：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">X bar(const T&amp; y,const T&amp; z){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp; return X(y,z);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">变成：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">bar(X&amp; result){</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp; result . X::X(y,z);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp; return; </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">无需copy ctor了</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">编译器的优化：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如上所述bar中返回了具名数值 named value，因此编译器有可能自己优化，方法是以result取代named return value</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">bar(X&amp; result){_result.X::X(); 直接处理result 并不处理变量xx然后复制给result 这样就优化了}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">这个优化的激活需要class提供一个copy ctor~~~~~~</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">Copy ctor 要不要:</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">如果一个class 符合bitwise的要求那么此时member wise 的拷贝已经高效简洁 无需加入了</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">但是如果class需要大量的member wise 初始化操作，如用传值方式返回objects，如果是这样提供一个copy ctor 可以激活nRV named return value 优化，这就很合理了</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">成员们的初始化过程：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">什么时候必须用初始化列表：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">1.初始化一个reference时 2.初始化一个const member 3.调用父类ctor而且有参数时4调用member class ctor 有参数 </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">其他情况呢：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">class word{string name;int cnt;public: name=0;cnt=0;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">编译器可能这么做:</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">word::word{</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; name.String::string();调用string的default ctor</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; string tmp=string(0);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">_name.string::operator=(tmp);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">tmp.string::~string();</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">cnt=0;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">显然name放到初始化列表会更有效率 ，会变成</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">name.String::String(0);</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">而cnt这种内建类型则没有关系，放不放到初始化列表没有效率上的差别</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">初始化列表究竟让编译器做了什么？？？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">编译器会一个个操作list中的式子，以适当次序在ctor内安插初始化操作在任何explicit user code 之前。</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">注意的地方：</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list中的次序是按照members声明次序决定而不是list 中的排列顺序决定。</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">例如：class x{int i;int j; X(int val):j(val),i(j)}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">错了 i先声明则i首先赋予val 然后用未初始化的j赋给i。。。</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">可以这样X::X(int val):j(val){i=j;}</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">由于会安插在explicit code 之前 所以没问题 会变成 j=val;&nbsp;&nbsp; i=j;</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">可否用member functions 初始化成员？？</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">答案是可以的，因为和objects相关的this指针已经构建妥当，只是要注意函数调用的member是否已经构建妥当了即可</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp; -&nbsp; - ----------&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --疲惫的结束线-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - -&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp; - --&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -----</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">name return value TEST:</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">~~~~1 cl /od 不开优化</font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">#include &lt;iostream&gt;<br>using namespace std;<br>class RVO<br>{<br>public: </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; RVO(){printf("I am in constructor\n");}<br>&nbsp;&nbsp;&nbsp; RVO (const RVO&amp; c_RVO) {printf ("I am in copy constructor\n");}<br>&nbsp;&nbsp;&nbsp; ~RVO(){printf ("I am in destructor\n");}<br>&nbsp;&nbsp;&nbsp; int mem_var;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>};<br>RVO MyMethod (int i)<br>{<br>&nbsp;&nbsp;&nbsp; RVO rvo1;<br>&nbsp;&nbsp;&nbsp; rvo1.mem_var = i;<br>&nbsp;&nbsp;&nbsp; return (rvo1);<br>}<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; RVO rvo;rvo=MyMethod(5); <br>} </font></p> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">输出： </font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in constructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //rvo 创建<br>I am in constructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo1创建<br>I am in copy constructor // rvo1赋值给hiddern<br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo1解构<br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // hiddern解构<br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; rvo 解构</font></p></blockquote><pre><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">A MyMethod (A &amp;_hiddenArg, B &amp;var)
{
   A retVal;
   retVal.A::A(); // constructor for retVal
   retVal.member = var.value + bar(var);
   _hiddenArg.A::A(retVal);  // the copy constructor for A
   return;
retVal.A::~A();  // destructor for retVal

}</font></pre><pre><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">A MyMethod(A &amp;_hiddenArg, B &amp;var)
{
   _hiddenArg.A::A();
   _hiddenArg.member = var.value + bar(var);
   Return
}</font></pre><pre><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">~~~~2 cl /o2 代码同上</font></pre><pre><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">output</font></pre>
<blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in constructor&nbsp; //rvo创建<br>I am in constructor&nbsp; //hiddern 创建<br>I am in destructor&nbsp;&nbsp; //hiddern 解构<br>I am in destructor&nbsp;&nbsp; //rvo解构</font></p></blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"><strike>我不明白的是hiddern 怎么传给rvo ，我猜可能是编译器按照bitwise的复制方式进行的,此时编译器并没有直接建构结果于rvo上</strike> ，看看下面的试验：</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">注：明白了， 结果直接建构在hiddern，然后通过operator = 传给rvo 。没有copy ctor因为拷贝构造函数是负责初始化的，而operator = 才是用来赋值的.</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">经过代码证明是对的，如果重载赋值运算符 输出变成：</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in constructor&nbsp; //rvo创建<br>I am in constructor&nbsp; //hiddern 创建</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in operator =&nbsp;&nbsp; //赋值操作~~<br>I am in destructor&nbsp;&nbsp; //hiddern 解构<br>I am in destructor&nbsp;&nbsp; //rvo解构</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">~~~~3 cl /od </font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">#include &lt;iostream&gt;<br>using namespace std;<br>class RVO<br>{<br>public: </font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;&nbsp;&nbsp; RVO(){printf("I am in constructor\n");}<br>&nbsp;&nbsp;&nbsp; RVO (const RVO&amp; c_RVO) {printf ("I am in copy constructor\n");}<br>&nbsp;&nbsp;&nbsp; ~RVO(){printf ("I am in destructor\n");}<br>&nbsp;&nbsp;&nbsp; int mem_var;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>};<br>RVO MyMethod (int i)<br>{<br>&nbsp;&nbsp;&nbsp; RVO rvo1;<br>&nbsp;&nbsp;&nbsp; rvo1.mem_var = i;<br>&nbsp;&nbsp;&nbsp; return (rvo1);<br>}<br>void abc(RVO&amp; i){<br>}<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; RVO rvo=MyMethod(5);&nbsp; //此时定义和赋值放到了一个表达式子<br>&nbsp;&nbsp;&nbsp; return 0;<br>} </font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">output: </font></p>
<blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in constructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo1 创建 注意 跟上面的第一种情况下的hiddern一样 rvo并没有调用ctor<br>I am in copy constructor&nbsp;&nbsp; // rvo1 拷贝构造给rvo 此时没有hiddern了 直接构建rvo了<br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo1 析构<br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo1 解构</font></p></blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">~~~~3 cl /o2&nbsp; 再来~~~~ NRV出马 </font></p>
<blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">I am in constructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo构建了&nbsp; <br>I am in destructor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // rvo析构了</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">此时 mymethod中的一切都直接反映在rvo身上 </font></p></blockquote>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">ok~~~~~4个代码完全一样构造析构拷贝函数个数由2-6不等~~~over~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p><pre><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></pre>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3">&nbsp;</font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"></font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"></font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"></font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"></font></p>
<p><font face="YaHei Consolas Hybrid" color="#aec2fd" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/108832.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-03 22:23 <a href="http://www.cppblog.com/zqsand/archive/2010/03/03/108832.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入探索C++对象模型读书笔记 (一)</title><link>http://www.cppblog.com/zqsand/archive/2010/03/03/108780.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Wed, 03 Mar 2010 05:58:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/03/03/108780.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/108780.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/03/03/108780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/108780.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/108780.html</trackback:ping><description><![CDATA[<p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">寒假基本读了一遍，现在再读一遍，做下笔记。</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">笔记当做的精炼而有意义，而后回顾可知其意，回其味，方有成效</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">---------------------------------------------------------------------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">C语言：数据和操纵数据的方法分开声明,方法被写成函数处理外部数据</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">C++:数据和方法的组合封装ADT 更安全 支持继承 清晰</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">封装在空间上的代价：</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">如果仅仅是普通继承则并没有什么代价，因为每个数据成员直接内涵在每一个class对象中，和c中的struct一样，而member function如果不是inline的则只会产生一个实体，而inline会在每一个使用的模块产生一个函数实体</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">c++在空间和存取效率的代价主要由virtual带来：</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">virtual function 机制： vtable vptr 执行期绑定</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">virtual class 机制：</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">还有多重继承下的额外负担（子类转换成第二个父类的时候）</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">----------------------------------------------------------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">c++对象模型：也就是我们怎么在内存中安排各个数据成员以及成员函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">1.简单对象模型~ 对象由各个slot组成，每一个slot包含指针，指向各个成员</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">2.表格驱动模型~ 对象含有两个指针，一个指向成员数据表，另一个指向成员函数表</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">3.c++实际对象模型~ 非静态数据被放在对象内，而静态数据成员放在对象外（显然啊，他属于类），成员函数</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">&nbsp; 不管静态或者非静态都放在对象外面</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">&nbsp; Virtual functions ：每个class产生一堆指向vitrualfunctions的指针，放在vtables中，每个对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">&nbsp; 含有vptr 指向vtable vptr的设定，重置均有class的ctor，dtor，copy assignment 运算符自动完成</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">&nbsp; 优点：空间和存储效率 缺点：如果对象模型的nonstatic data members 有所修改，也就是对象内部布局</font><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">有所更改，那么使用该对象的应用程序需要重新编译.</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">虚拟继承：不管基类被派生了多少次，永远只有一个实体（菱形继承最下面对象中只有一个顶部类实体）</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">继承的实现：一种可以用basetable 在basetable中指向一个baseclass的地址，但这会随着继承深度越来越深变得慢</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">现在采用的方法之后记录~~~ ：P</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">书中的程序：对象模型对程序的影响：</font></p> <p><font color="#c1af79">X foobar(){<br>&nbsp;&nbsp;&nbsp; X xx;<br>&nbsp;&nbsp;&nbsp; X *px = new X;<br>&nbsp;&nbsp;&nbsp; xx.foo();<br>&nbsp;&nbsp;&nbsp; px-&gt;foo(); //foo是一个virtual function<br>&nbsp;&nbsp;&nbsp; delete px;<br>&nbsp;&nbsp;&nbsp; return xx;<br>}<br>//调用处 X _result;<br>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foobar(_result);<br>void foobar(X&amp; _result){<br>&nbsp;&nbsp;&nbsp; _result.X::X();//构造result<br>&nbsp;&nbsp;&nbsp; px = _new(sizeof(X));<br>&nbsp;&nbsp;&nbsp; if(px!=0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; px-&gt;X::X;<br>&nbsp;&nbsp;&nbsp; foo(&amp;_result);//使用result取代xx但是不激活virtual机制<br>&nbsp;&nbsp;&nbsp; (*px-&gt;vtbl[2])(px);//使用virtual机制扩展px-&gt;foo();<br>&nbsp;&nbsp;&nbsp; if(px!=0){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*px-&gt;vtbl[1])(px);//使用virtual调用destructor<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete px;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; //不用使用named return statement<br>&nbsp;&nbsp;&nbsp; return ;<br>} </font> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">------------------------------------------------------------------------------------</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">关键词带来的麻烦~~</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">struct 和 class 在C++中可以混用，并不是由于使用哪一个决定其特性，只是给人的感觉不同罢了class更像是c++中继承的代名词 struct更像C中的数据集</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">如果需要向C函数传递数据集合可以使用struct以保证对象模型的支持</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">使用struct完全可以声明各种class的特性</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">对象的差异</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">1.程序模型procedural model&nbsp; 同c一样</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">2.抽象数据类型模型 ADT object-base 抽象指的是一族表达式（public接口）的提供，具体计算方法未明</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">3.面向对象 oo 有一些彼此相关的模型通过一个抽象的baseclass用以提供公共接口封装起来</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">OO中程序员可能需要处理一个未知实体，在执行点之前无法确定，这是由pointers和reference实现的而在ADT中程序员处理的是一个拥有固定单一类型的实体，编译时期就已经确定了~</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">c++中的多态：1.把derived class的指针转化成一个基类的指针 2virtualfunctions 3.dynamic_cast 和typeid运算符</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">多态主要是经由一个共同的接口来影响类型的封装，这个接口通常被放置在抽象的baseclass中，这个共享接口是以virtual functions机制来引发的，可以在执行期间根据object的真正类型解析出到底是哪一个函数实体被调用。</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">我们的代码可以避免由于增加某一个特定的derived 实体而改变，只需要新的derivedclass重写这样的接口便可。</font></p> <p><font color="#c1af79">//测试指针引用的多态<br>#include &lt;iostream&gt;<br>&nbsp;&nbsp;&nbsp; using namespace std;<br>&nbsp;&nbsp;&nbsp; struct Point{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point(float x=0.):_x(x){}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float x(){return _x;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void x(float xval){_x=xval;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void&nbsp; out(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"I am a Point"&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; protected:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float _x;<br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; struct Point2d:public Point{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point2d(float x=0.,float y=0.):Point(x),_y(y){}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float y(){return _y;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void y(float yval){_y=yval;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void out(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"I am a Point2d"&lt;&lt;endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; protected:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float _y;<br>&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp; int main(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point pt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point2d pt2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point* ptr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point2d* ptr2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pt.out(); pt2.out();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pt=pt2;pt.out();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr=&amp;pt2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr-&gt;out();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*ptr).out();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Point&amp; ptref=pt2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptref.out();<br>&nbsp;&nbsp;&nbsp; } </font> <p><font color="#c1af79">output: </font> <p><font color="#c1af79">I am a Point<br>I am a Point2d<br>I am a Point<br>I am a Point2d<br>I am a Point2d<br>I am a Point2d</font></p><font face="YaHei Consolas Hybrid" size="3"></font> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">指针和引用可以实现多态，因为指针和引用的赋值只是改变其指向的范围，并没有触及对象模型的改变，因此可以产生多态的效果。而value的赋值操作会导致对象模型的切割，从而真实的改变了对象的内部模型与类型，失去了多态的效果。oo 不支持对对象的直接处理</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">指针的类型：</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">不同的指针从内存角度来看没什么不同，只是占据了一个word的空间，但是指针的类型会告诉编译器如何解释某个特定地址中的内存内容以及大小</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">OB设计也就是ADT设计比OO设置更有效率因为其所有函数引发操作均在编译器确定OO需要一些运行时确定，对象构建起来不需要设置virtual机制</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">比OO紧凑因为无需支持virtual机制从而没有额外负担</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3">但是OB相对来说弹性较小~~</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#c1af79">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#c1af79" size="3"></font></p> <p><font color="#c1af79"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/108780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-03-03 13:58 <a href="http://www.cppblog.com/zqsand/archive/2010/03/03/108780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>More Effective C++ (1)</title><link>http://www.cppblog.com/zqsand/archive/2010/01/18/105931.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Mon, 18 Jan 2010 06:16:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/01/18/105931.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/105931.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/01/18/105931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/105931.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/105931.html</trackback:ping><description><![CDATA[
<p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">第四章&nbsp; 效率</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;条款16 记住80-20准则</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">大约20%的代码使用了80%的资源，程序的整体性能是由该程序的一小部分代码所决定的~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">可行的办法是使用程序分析器（profiler）来找到导致性能瓶颈的拿20%的程序~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">而且要针对造成瓶颈的资源来使用相应的分析器~</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#ffff80">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;条款17&nbsp; 考虑使用延迟计算</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">延迟计算： 也就是说知道程序要求给出结果的时候才进行运算~ 很好理解，和操作系统中的cow copy on write 一个原理~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">四个使用场景：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~1~ 引用计数 ：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">　　class String{&#8230;};</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">String s1 = &#8220;hello&#8221;;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">String s2 = s1 ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //call string Copy ctor</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">通常情况下，s2赋值后会有一个hello的拷贝，者通常需要使用new操作符分配内存，之后strcpys1</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">的数据给他，但如果下面的操作如下的话：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cout &lt;&lt; s1 ;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cout &lt;&lt; s1 + s2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这种情况下如果只增加s1的引用计数，而s2只是共享s1的值就可以了。只有在需要对s2进行修改或者s1进行修改时，才需要真正拷贝给s2一个副本，引用计数的实现在29条款</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~2~区分读写操作</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如： String s = &#8220;homer&#8217;s all&#8221;;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cout&lt;&lt; s[3];</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">s[3] = &#8216;x&#8217;;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">在进行读操作时，使用引用计数是开销很小的，然而写操作必须生成新的拷贝。通过条款30的代理类我们可以把判断读写操作推迟到我们能够决定哪个是正确操作的时候</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~3~延迟读取</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">假设程序使用了包含许多数据成员的大对象，这些对象必须在每次程序运行的时候保留下来，因此存进了数据库。某些时候从database中取出所有数据是没有必要的，比如他只访问该对象中的一个数据成员。此时，应该对对象进行处理，只有对象内部某一个特定的数据成员被访问的时候才把他取出来。类似于os中的按需换页~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class LargeObject{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp;&nbsp; LargeObject(ObjectID id);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">const string&amp; field1() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">int field2() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">double field3() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">const string&amp; field4() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">private:</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">ObjectID id;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">mutable string* field1value;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">mutable int&nbsp;&nbsp; * fieldValue;</font></p> <p><font color="#ffff80"><font face="YaHei Consolas Hybrid" size="3">}</font><font face="YaHei Consolas Hybrid" size="3">;</font></font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">LargeObject::LargeObject(ObjectID id):oid(id),fieldValue(0),&#8230;{}</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">const string&amp; LargeObject::field1()const{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; if(fieldValue == 0){</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //read the data for field 1 from database and make field1 point to it</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; }</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; return&nbsp; *field1Value; </font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">实施lazy fetching 任何成员函数都需要初始化空指针以指向有效数据。但是const成员函数中，试图修改数据编译器会报错。所以声明字段指针为 mutable ，表示任何函数都可以修改,即便在const成员函数中也可以~ 条款28中的智能指针可以让这一方法更灵活</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~3~延迟表达式求值</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">数值计算领域，也在使用延迟计算。例如</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">matrix&lt;int&gt; m1(1000,1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">matrix&lt;int&gt; m2(1000,1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">matrix&lt;int&gt; m3 = m1 + m2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如果此时计算出m3的话运算量非常之大~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">但是如果此时程序为：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">m3 = m4*m1;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">那么刚才的计算就没必要了</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如果cout&lt;&lt; m3[4];</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">我们只需要计算m3[4]就可以了，其他的值等到确实需要他们的时候才予以计算~如果运气够好的话永远不需要计算~ </font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">总结，延迟计算只有当软件在某种程度下可以被避免时候才有意义~只有延迟计算得到的好处大于设计它与实现它花费的精力时才有意义~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款18： 分期摊还预期的计算开销</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">提前计算~ over-eager evaluation 在系统要求你做某些事情之前就做了他~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如：大量数据的集合</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">template&lt;class NumericalType&gt;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class DataCollection}{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">public:</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp; NumericalType min() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp; NumericalType max() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp; NumericalType avg() const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">使用提前计算，我们随时跟踪目前集合的最大最小平均值，这样 min max avg被调用时候，我们可以不用计算立刻返回正确的数值~~ </font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">提前计算的思想便是：如果预计某个计算会被频繁调用，你可以通过设计你的数据结构以更高效的办法处理请求，这样可以降低每次请求的平均开销~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">最简单的做法为 缓存已经计算过并且很可能不需要重新计算的那些值~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如在数据库中存有很多办公室的电话号码，程序在每次查询电话时先查询本地的缓存如果没找到再去访问数据库，并且更新缓存，这样使用缓存平均访问时间要大大减小。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">预处理也是一种策略。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如设计动态数组的时候，当索引下标大于已有最大范围时候，需要new出新的空间，如果申请两倍于索引的大小的话就可以避免频繁的申请操作~~~</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#ffff80">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款 19 ： 了解临时对象的来源</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如果一个对象被创建，不是在堆上，没有名字，那么这个对象就是临时对象。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">通常产生于： 为了使函数调用能够成功而进行的隐式转换，或者函数返回对象是进行的隐式转换。由于构造和析构他们带来的开销可以给你的程序带来显著的影响，因此有必要了解他们~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~1首先考虑为了函数调用能通过产生的临时对象的情况</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">传给某个函数的对象的类型和这个函数所绑定的参数类型不一致的情况下会出现这种情况。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">size_t count(const string&amp; str,char ch);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">函数定义为计算str中ch的数量</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">char buffer[100];</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cout&lt;&lt;count(buffer,&#8216;c&#8217;);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">传入的是一个char数组，此时编译器会调用str的构造函数，利用buffer来创建一个临时对象。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">在调用完countChar语句后这个临时对象就被自动销毁了~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">仅当传值或者const引用的时候才会发生这样的类型转换~当传递一个非常量引用的时候，不会发生。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">void uppercasify(string&amp; str); //change all chars in str to upper case;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">在这个例子中使用char数组就不会成功~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">因为程序作者声明非常量引用也就是想让对引用的修改反映在他引用的对象身上，但是如果此时生成了临时对象，那么这些修改只是作用在临时对象身上，也就不是作者的本意了。所以c++禁止非常量引用产生临时对象。</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~2 函数返回对象时候会产生临时对象</font></p> <blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如： const Number operator + ( const Number&amp; lhs,const Number&amp; rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这个函数返回一个临时对象，因为他没有名字，只是函数的返回值。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">条款20中 ，会介绍让编译器对已经超出生存周期的临时对象进行优化</font></p></blockquote> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款20： 协助编译器实现返回值优化</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">返回值优化：返回带有参数的构造函数。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cosnt Rational operator * (cosnt Rational&amp; lhs,const Rational&amp; rhs){</font></p> <p><font color="#ffff80"><font face="YaHei Consolas Hybrid" size="3">&nbsp;&nbsp;&nbsp; return Rational(lhs.numerator()*rhs.numerator(),lhs.denomiator()*rhs.denominator()</font><font face="YaHei Consolas Hybrid" size="3">};</font></font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">c++允许编译器针对超出生命周期的临时对象进行优化。因此如果调用Rational c=a*b；</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">c++允许编译器消除operator*内部的临时变量以及operator*返回的临时变量，编译器可以把return表达式所定义的返回对象构造在分配给c的内存上。如果这样做的话那么调用operator*所产生的临时对象所带来的开销就是0~ 我们可以把operator 声明为内联函数而去除调用构造函数带来的开销~</font></p> <p><font color="#ffff80">#include &lt;iostream&gt;<br>#include &lt;string&gt;<br>#include "time.h"<br>using namespace std;<br>char buffer[100]; <br>class number{<br>public:<br>&nbsp;&nbsp;&nbsp; const friend&nbsp; number operator * (const number&amp; rhs,const number lhs);<br>&nbsp;&nbsp;&nbsp; number(){}<br>&nbsp;&nbsp;&nbsp; number(int b):a(b){}<br>&nbsp;&nbsp;&nbsp; number(const number&amp; rhs){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = rhs.a;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int a; <br>};<br>const number operator*(const number&amp; rhs,const number lhs){<br>&nbsp;&nbsp;&nbsp; number res;<br>&nbsp;&nbsp;&nbsp; res.a = rhs.a * lhs.a;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return res;<br>&nbsp;&nbsp;&nbsp; /*return number(rhs.a*lhs.a);*/<br>}<br>//CLOCKS_PER_SEC<br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; clock_t start = clock();<br>&nbsp;&nbsp;&nbsp; number A(5);number B(6);<br>&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;100000000;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; number C = A*B; </font> </p><p><font color="#ffff80">&nbsp;&nbsp;&nbsp; clock_t end = clock();<br>&nbsp;&nbsp;&nbsp; cout&lt;&lt;double(end-start)/CLOCKS_PER_SEC&lt;&lt;endl;<br>}</font> </p><p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">通过上面的程序运行 如果没有返回值优化 运行时间 15.9s 优化后是 10.1s </font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">还是很显著的么 快了33% ，如果这种情况出现在程序的热点处~效果就很好了</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款21 ： 通过函数重载避免隐式类型转换</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例子：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class upint{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> public:</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> upint();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> upint(int value);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cosnt upint operator+(const upint&amp;lhs,const upint&amp;rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">upint up1,up2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">upint up3 = up1+up2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">upi3 = up1 +10;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">upi4 = 10+ upi2;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这些语句也可以通过，因为创建了临时对象，通过带有int的构造函数产生了临时的upint对象，如果我们不愿意为这些临时对象的产生与析构付出代价，我们需要做什么：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">我们声明 cosnt upint operator+(cosnt upint&amp;lhs,int rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">cosnt upint operator+(int lhs,const upint&amp; rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">就可以去除临时对象产生了~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">但是如果我们写了 const upint operator+(int lhs,int rhs); // 错了~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">c++规定，每一个被重载的运算符必须至少有一个参数属于用户自定义类型，int并不是自定义类型所以上面的不对的</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">同样的如果希望string char* 作为参数的函数，都有理由进行重载而避免隐形类型转换（仅仅在有必要的时候，也就是说他们可以对程序效率起到很大帮助的时候~）</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款： 考虑使用 op = 来取代 单独的 op运算符</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class Rational{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">public:</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; Rational&amp; operator+=(const Rational&amp; rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; Rational&amp; operator-=(const Rational&amp; rhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">const Rational operator+(cosnt Rational&amp; lhs,const Rational &amp; rhs){</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp;&nbsp; return Rational(lhs)+=rhs;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">利用+= -=来实现+ -可以保证运算符的赋值形式与单独使用运算符之间存在正常的关系。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">Rational a,b,c,d,result;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">result = a+ b+c+d; // 可能要用到3个临时对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">result +=a;result+=b;result+=c; //没有临时对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">前者书写维护都更容易，而且一般来说效率不存在问题，但是特殊情况下后者效率更高更可取</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">注意：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> 如果+的实现是这样的：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> const T operator+ (constT&amp; lhs,const T&amp;rhs){</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp;&nbsp;&nbsp; T result(lhs);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp;&nbsp;&nbsp; return result += rhs;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"> }</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这个模版中包含有名字对象result，这个对象有名字意味着返回值优化不可用~~~~~~~~&#183;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;条款23 ： 考虑使用其他等价的程序库</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">主旨：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">提供类似功能的程序库通常在性能问题上采取不同的权衡措施，比如iostream和stdio，所以通过分析程序找到软件瓶颈之后，可以考虑是否通过替换程序库来消除瓶颈~~~~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&#183;&#183;&#183;&#183;&#183;&#183;条款24 : 理解虚函数，多重继承，虚基类以及 RTTI 带来的开销</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">虚函数表：vtabs 指向虚函数表的指针 vptrs</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">程序中每个声明了或者继承了的虚函数的类都具有自己的虚函数表。表中的各个项就是指向虚函数具体实现的指针。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class c1{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; c1();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual ~c1();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual void f1();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual int f2(char c)const;</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual void f3(const string&amp; s);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">c1 的虚函数表包括： c1::~c1 c1::f1 c1::f2 c1::f3</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class c2:public c1{</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; c2();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual ~c2();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual void f1();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; virtual void f5(char *str);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">它的虚函数表入口指向的是那些由c1声明但是c2没有重定义的虚函数指针：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">c2::~c2&nbsp; c2::f1 c1::f2 c1::f3 c2::f5</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">所以开销上： 必须为包含虚函数的类腾出额外的空间来存放虚函数表。一个类的虚函数表的大小取决于它的虚函数的个数，虽然每一个类只要有一个虚函数表，但是如果有很多类或者每个类具有很多个虚函数，虚函数表也会占据很大的空间，这也是mfc没有采用虚函数实现消息机制的一个原因。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">由于每一个类只需要一个vtbl的拷贝，把它放在哪里是一个问题：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">一种：为每一个需要vtbl的目标文件生成拷贝，然后连接时取出重复拷贝</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">或者：更常见的是采用试探性算法决定哪一个目标文件应该包含类的vtbl。试探：一个类的vtbl通常产生在包含该类第一个非内联，非纯虚函数定义的目标文件里。所以上面c1类的vtbl将放在c1::~c1 定义的目标文件里。如果所有虚函数都声明为内联，试探性算法就会失败，在每一个目标文件就会有vtbl。所以一般忽略虚函数的inline指令。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如果一个类具有虚函数，那么这个类的每一个对象都会具有指向这个虚函数表的指针，这是一个隐藏数据成员vptr~被编译器加在某一个位置。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">此处第二个开销：你必须在每一个对象中存放一个额外的指针~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">如果对象很小这个开销就十分显著~~因为比例大~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">此时 void makeCall(c1* pc1){</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">&nbsp;&nbsp; pc1-&gt;f1();</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">翻译为 (*pc1-&gt;vptr[i])(pc1);</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">根据vptr找到vtbl 这很简单，</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">在vtbl找到调用函数对应的函数指针，这个步骤也很简单，因为编译器为虚函数表里的每一个函数设置了唯一的索引</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">然后调用指针所指向的函数~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这样看来，调用虚函数与普通函数调用的效率相差无几，只多出几个指令。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">虚函数真正的开销与内联函数有关~：在实际应用中，虚函数不应该被内联，因为内联意味着在编译时刻用被调用函数的函数体来代替被调用函数。但是虚函数意味着运行时刻决定调用哪个一函数，so~~~虚函数付出的第三个代价啊：~不能内联（通过对象调用虚函数的时候，这些虚函数可以内联，但是大多数虚函数通过指针或者以用来调用的）。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">~多重继承的情况</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">多重继承一般要求虚基类。没有虚基类，如果一个派生类具有多个通向基类的继承路径，基类的数据成员会被复制到每一个继承类对象里，继承类与基类间的每一条路径都有一个拷贝。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">有了虚基类，通常使用指向虚基类的指针作为避免重复的手段，这样需要在对象内部嵌入一个或者多个指针~也带来了一定的开销~</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">例如菱形继承 ： </font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class A{};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class B:virtual public A{};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class C:virtual public A{};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">class D:public B,public C{};</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">这里A是一个虚基类，因为B和C虚拟继承了他。</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">对象 D 的布局：</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">B data</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">vptr</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">pointer to virtual base class</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">C data</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">vptr</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">pointer to virtual base class</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">D data members</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">A data members</font></p> <p><font face="YaHei Consolas Hybrid" color="#ffff80" size="3">vptr</font></p> <p><font face="YaHei Consolas Hybrid" color="#8000ff" size="3"><font color="#ffff80">上面四个类，只有三个vptr，因为B和D可以共享一个vptr</font>&nbsp; <font color="#ff0000">（为啥？）</font></font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">现在我们已经看到虚函数如何使对象变得更大，以及为何不能把它内联了~</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">下面我们看看RTTI的开销 runtime type identifycation 所需要的开销</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">通过rtti我们可以知道对象和类的有关信息，所以肯定在某个地方存储了这些供我们查询的信息，这些信息被存储在type_info 类型的对象里，你可以通过typeid运算符访问一个类的type_info对象。</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">每个类仅仅需要一个RTTI的拷贝，规范上只保证提供哪些至少有一个虚函数的对象的准确的动态类型信息~</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">why？和虚函数有啥关系~ 因为rtti设计在vtbl里</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">vtbl的下标0包含指向type_info对象的指针。所以使用这种实现方法，消费的空间是vtbl中占用一个额外的单元再加上存储type_info对象所需要的空间。</font></p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#0080ff" size="3">------------------------罪恶的结束线 OVER~------------------------------------------</font></p><img src ="http://www.cppblog.com/zqsand/aggbug/105931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-01-18 14:16 <a href="http://www.cppblog.com/zqsand/archive/2010/01/18/105931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>断言的使用</title><link>http://www.cppblog.com/zqsand/archive/2010/01/17/105886.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sun, 17 Jan 2010 11:36:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/01/17/105886.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/105886.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/01/17/105886.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/105886.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/105886.html</trackback:ping><description><![CDATA[
<p>解决项目的问题，意识到断言的重要性。如果一个程序在某处遇到了非法的值，那么最好的情况便是在此刻停下报错，最坏的情况便是程序不吭不响的执行着~~直到你发现他执行的方式极为诡异，此时，你要花九牛二虎之力才能找到错误所在之处~~~~</p> <p>学习一下断言吧：</p> <p><font size="3"><font face="YaHei Consolas Hybrid" color="#008000">&#183;&#183;&#183;&#183;&#183;&#183;&#183;什么是断言</font></font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">在某处判断某一个表达式的值为真或者假，如果假则输出错误消息并停止程序的执行~</font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">assert是宏，而不是函数，只在debug版本中有效，因此无需在release版本删除。</font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">&#183;&#183;&#183;&#183;&#183;&#183;&#183;哪几种断言</font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">MFC </font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">ASSERT</font></p> <p>void foo(char* p,int size)<br>{<br>ASSERT(p != 0); // 验证缓冲区指针<br>ASSERT((size &gt;= 100); // 确认缓冲区大小至少为100字节<br>// foo 函数的其它计算过程<br>}<br>如果没有定义_DEBUG预处理符，则该语句不会真正生成代码。Visual C++会在调试模式编译时自动定义_DEBUG，而在发行模式下，该预处理符是不存在的。如果定义了_DEBUG，则上述两个断言生成的代码类如： <br>//ASSERT(p != 0);<br>do<br>{<br>if(!(p != 0) &amp;&amp; AfxAssertFailedLine(__FILE__, __LINE__))<br>AfxDebugBreak();<br>} while(0);<br>//ASSERT((size &gt;= 100);<br>do<br>{<br>if(!(size &gt;= 100) &amp;&amp; AfxAssertFailedLine(__FILE__,__LINE__))<br>AfxDebugBreak();<br>}while(0);  </p><p><font face="YaHei Consolas Hybrid" color="#008080" size="3">ASSERT_KINDOF(classname,pObject); ASSERT_KINDOF(CDocument,pDocument);</font></p> <p><font face="YaHei Consolas Hybrid" color="#008080" size="3">检验pObject指向的对象是classname类的一个对象或者其派生类的对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#008080" size="3">ASSERT_VALID(pObject); pObject 必须是一个派生于CObject类的类对象，会调用其重写的AssertValid函数 ，例如</font></p> <p>如果使用应用向导或类向导生成基于MFC的类，通常会得到AssertValid()的骨架，最好改写这些骨架代码以增加最基本的完整性检查。下面是一个典型的例子，类Sample从CObject继承，假定它含有职员名字及其薪水： <br>class Sample : public CObject<br>{<br>&nbsp;&nbsp;&nbsp; protected:<br>&nbsp;&nbsp;&nbsp; CString m_Name; // 职员名字<br>&nbsp;&nbsp;&nbsp; double m_Salary; // 薪水<br>public:<br>&nbsp;&nbsp;&nbsp; Sample(LPCTSTR name,double salary) : m_Name(name), m_Salary(salary) {}<br><em>&nbsp;&nbsp; #ifdef _DEBUG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void AssertValid() const;<br>&nbsp;&nbsp;&nbsp; #endif</em><br>};<br><em>#ifdef _DEBUG<br>void Sample::AssertValid() const<br>{<br>&nbsp;&nbsp;&nbsp; CObject::AssertValid(); // 验证基类<br>&nbsp;&nbsp;&nbsp; ASSERT(!m_Name.IsEmpty()); // 验证职员名字<br>&nbsp;&nbsp;&nbsp; ASSERT(m_Salary &gt; 0); // 验证薪水<br>}<br>#endif</em>  </p><p><font face="YaHei Consolas Hybrid" color="#408080" size="3">CRT assertion</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">_ASSERT 和&nbsp; _ASSERTE 后一个会在出错时同时打印出条件判断句</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">ANSI</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">assert()</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">注意：assert用于检测非法的输入，但是合法的输入并不一定是正确的，例如：</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">int pB = (int*)malloc(sizeof(int)*1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">assert(pB!=NULL) //错误的使用assert 他会在release版本失效~也就是说assert不应该对程序产生副作用</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">正确的做法：</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">int pB = (int*) malloc(sizeof(int)*1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">if(pB == NULL)</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">{<br>&nbsp;&nbsp; //错误处理</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">else{</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">另一个例子：</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">void draw(){</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">&nbsp;&nbsp; CFigure* pF = getCF();</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">&nbsp;&nbsp; assert(pf!=NULL);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">&nbsp;&nbsp; if(pf == NULL){}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">&nbsp;&nbsp; else{</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">&nbsp;&nbsp; }</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">此处，对于getCF来说返回值为NULL是非法的，如果他的返回值可能为null就没必要加上assert语句。</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">而下面的if语句则是为了防止release版本出现null指针的情况。 </font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">VERIFY()</font></p> <p><font color="#408080">由于ASSERT仅在程序的调试版起作用，测试表达式总是被动的。也就是说，它们不能包含赋值、增量、减量等真正改变数据的操作。但有时候我们需要验证一个主动表达式，比如赋值语句。这时可以使用VERIFY代替ASSERT。下面是一个例子： <br>void foo(char* p,int size)<br>{<br>char* q; // 指针的副本<br><em>VERIFY(q = p);</em> // 拷贝指针并执行验证<br>ASSERT((size &gt;= 100); // 确保缓冲区大小至少为100字节<br>// 执行 foo 的其它操作<br>}<br>在调试模式下ASSERT和VERIFY是相同的。但在release模式下，VERIFY能够继续对表达式求值（但不再进行断言检验），而ASSERT语句在效果上就如同已经删除了一样。 <br>尽管在MFC源代码中可以找到一些应用VERIFY的例子，但ASSERT用得更为普遍。一些程序员总是完全避免使用VERIFY，因为他们已经习惯于使用被动断言。请记住，如果在ASSERT语句中使用了主动表达式，编译器不会发出任何警告。在发行模式下编译时该表达式会被直接删除，从而导致程序运行的错误。由于发行版程序不含调试信息，这种类型的错误是很难找到原因的。 </font> </p><p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080">&nbsp;</font></p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font>&nbsp;</p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/105886.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-01-17 19:36 <a href="http://www.cppblog.com/zqsand/archive/2010/01/17/105886.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ RTTI (1)</title><link>http://www.cppblog.com/zqsand/archive/2010/01/03/104714.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sun, 03 Jan 2010 09:59:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2010/01/03/104714.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/104714.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2010/01/03/104714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/104714.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/104714.html</trackback:ping><description><![CDATA[
<p><font face="YaHei Consolas Hybrid">项目中遇到了 RTTI 先学一部分 c++ primer内容</font></p> <ol> <li> <div align="left"><font face="YaHei Consolas Hybrid" color="#ff0080" size="5"><u><strong>运行时类型识别：</strong></u></font></div></li></ol> <p align="left"><font face="YaHei Consolas Hybrid">程序可以使用<font color="#008000">基类的指针</font>或者引用来检索这些指针或引用所指对象的实际派生类型</font></p> <p align="left"><font face="YaHei Consolas Hybrid">标准库提供了两个操作符： </font></p> <blockquote> <p align="left"><font face="YaHei Consolas Hybrid">1. typeid&nbsp;&nbsp;&nbsp; 他可以返回指针或者引用所指向对象的实际类型</font></p> <p align="left"><font face="YaHei Consolas Hybrid">2. dynamic_cast&nbsp; 将基类类型的指针或引用安全的转为派生类的指针或者引用&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p></blockquote> <p align="left"><font face="YaHei Consolas Hybrid">对于不带虚函数的类在编译时期执行，否则在运行期间执行</font></p> <p align="left"><font face="YaHei Consolas Hybrid">使用时机：</font></p> <blockquote> <p align="left"><font face="YaHei Consolas Hybrid">基类指针调用派生类成员函数的话，一般应使用虚函数，这样编译器会根据对象的实际类型来选择正确的函数。但是某些情况下无法使用虚函数，那么此</font></p> <p align="left"><font face="YaHei Consolas Hybrid">时如果需要使用基类指针调用派生类成员函数便需要使用RTTI强制转换，而且<font color="#000080">必须检查转换是否成功</font>了</font></p></blockquote> <p align="left"><font face="YaHei Consolas Hybrid" color="#ff0000" size="4"><strong><u>(一) Dynamic_cast</u></strong></font></p> <p align="left"><font face="YaHei Consolas Hybrid">dynamic_cast 如果转换到指针失败则返回 0 如果转换到引用类型失败则抛出 bad_cast 异常</font></p> <p align="left"><font face="YaHei Consolas Hybrid">对指针操作：</font></p> <p align="left"><font face="YaHei Consolas Hybrid">if(Derived *derivedPtr = dynamic_cast&lt;Derived*&gt; (basePtr)){</font></p> <p align="left"><font face="YaHei Consolas Hybrid">&nbsp;&nbsp;&nbsp; //basePtr point to a derived object;</font></p> <p align="left"><font face="YaHei Consolas Hybrid">}else{</font></p> <p align="left"><font face="YaHei Consolas Hybrid">&nbsp;&nbsp; //basePtr point to a base object;</font></p> <p align="left"><font face="YaHei Consolas Hybrid">}</font></p> <p><font face="YaHei Consolas Hybrid">在 if 语句中进行检查 1.条件代码内部知道 derivedPtr 的类型 2.不可能在测试代码和使用代码中加入代码，也就是说不会在没有测试前就使用derivedPtr 3.如果失败外部不会使用未绑定的指针derivedPtr</font></p> <p><font face="YaHei Consolas Hybrid">对引用操作：</font></p> <p><font face="YaHei Consolas Hybrid">因为不存在空引用所以转换失败抛出异常</font></p> <p><font face="YaHei Consolas Hybrid">void f(const Base&amp; b){</font></p> <p><font face="YaHei Consolas Hybrid">&nbsp;&nbsp;&nbsp; try{</font></p> <p><font face="YaHei Consolas Hybrid">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const Derived &amp;d = dynamic_cast&lt;const Derived&amp;&gt; (b);</font></p> <p><font face="YaHei Consolas Hybrid">&nbsp;&nbsp;&nbsp; }catch(bad_cast){</font></p> <p><font face="YaHei Consolas Hybrid">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="YaHei Consolas Hybrid">}</font></p> <p><u><strong><font color="#ff0000" size="5">(二) typeid</font></strong></u> </p> <p>typeid(e) e是任意的表达式或者类型名</p> <p>Base *bp; </p> <p>Derived *dp;</p> <p>//compare type at run time of two objects</p> <p>if(typeid(*bp)==typeid(*dp)){</p> <p>&nbsp;&nbsp;&nbsp; //bp dp point to objects of the same type</p> <p>}</p> <p>if(typeid(*bp)==typeid(Derived)){</p> <p>&nbsp;&nbsp;&nbsp; //bp actually point to a Derived</p> <p>}</p> <p><strong><font color="#80ff00">注意typeid 测试的是 *bp 对象</font></strong></p> <p>//test always fails: The type of bp if pointer to Base</p> <p>if(typeid(bp)==typeid(Derived)){</p> <p>}</p> <p>Base* 将永远和Derived类型不同</p> <p>只有typeid 的操作数是带虚函数的类的对象的时候，才返回动态类型信息，测试指针返回指针的静态的，编译时类型</p> <p>（三 ）type_info 类</p> <p>作为typeid的返回值 提供</p> <p>t1==t2 t1!=t2 t.name() 的操作</p> <p>&nbsp;</p> <p>作为应用例子，可以实现一个类型敏感的相等操作符</p> <p>friend bool operator == (const base&amp; lhs, const base&amp; rhs){</p> <p>&nbsp;&nbsp;&nbsp; return typeid(lhs)==typeid(rhs) &amp;&amp; lhs.equal(rhs);</p> <p>}</p> <p>这样可以处理基类子类混合的相等判断了</p><img src ="http://www.cppblog.com/zqsand/aggbug/104714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2010-01-03 17:59 <a href="http://www.cppblog.com/zqsand/archive/2010/01/03/104714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TC-Practice-Record</title><link>http://www.cppblog.com/zqsand/archive/2009/12/26/104143.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sat, 26 Dec 2009 09:28:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2009/12/26/104143.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/104143.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2009/12/26/104143.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/104143.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/104143.html</trackback:ping><description><![CDATA[<p>tchs-1 none 1000pt DFS 利用进入的方向划分四个边</p> <p>tchs-2 250pt 直接算就行 我写了2分 500pt 暴力可以过，但是判断时候不能用stringstream 用算术判断 也可以用构造法 1000pt 每一位有三种可能性</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不用，保持不动，变化，分别递归计算value并更新结果即可，由于递归深度最多只有13层所以不会tle</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外也可以写出基数为3的循环来遍历每一种情况具体看代码</p> <blockquote> <p>&nbsp;&nbsp;&nbsp; for(i=0,A[0]++;A[i]&gt;2;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A[i]=0;A[i+1]++;<br>&nbsp; }</p></blockquote> <p>tchs-3 1000pt 要想使乘积最大，需要更多的3即可 500pt 又看错题了 ~~~ft 要注意题目一定要看清楚</p> <p>tchs-4 500pt 模拟题，好难懂 音乐的~ 可以都乘以16 用整数来计算 浮点会很烦~ 这种题思路要清晰 一步一步来</p> <p>tchs-5 250pt 简单题，注意使用double 可以用1.0*int就不用double()了还有 int(h+1e-9);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 500pt 简单题，把所有word提取出来然后排序，再依次插入标点即可，注意有些小技巧</p> <div class="wlWriterEditableSmartContent" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:ba518014-94a3-4598-a635-f08e37913488" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px">Code Snippet</div> <div style="background-color: #353535; max-height: 500px; overflow: auto; padding: 2px 5px; white-space: nowrap">&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">string</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">wordSort</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">string</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">)</span><br> &#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">{</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">vector</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">string</span><span style="background:#373737;color:#c0c0c0">&gt; </span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">,</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">string</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">,</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">for</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#d24400">int</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">;</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">size</span><span style="background:#373737;color:#c0c0c0">();</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">++) </span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]&gt;=</span><span style="background:#373737;color:#ffc4e1">&#39;A&#39;</span><span style="background:#373737;color:#c0c0c0">&amp;&amp;</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]&lt;=</span><span style="background:#373737;color:#ffc4e1">&#39;Z&#39;</span><span style="background:#373737;color:#c0c0c0">||(</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]&lt;=</span><span style="background:#373737;color:#ffc4e1">&#39;z&#39;</span><span style="background:#373737;color:#c0c0c0">&amp;&amp;</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]&gt;=</span><span style="background:#373737;color:#ffc4e1">&#39;a&#39;</span><span style="background:#373737;color:#c0c0c0">)){</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">!=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">){ </span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">push_back</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">);</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">}</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">+=</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">}</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">else{</span><br> <span style="background:#373737;color:#c0c0c0">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">!=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">){</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">push_back</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">);</span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">}</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">+=</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">}</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">!=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">)</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">push_back</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">A</span><span style="background:#373737;color:#c0c0c0">);</span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">!=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">)</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">push_back</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">B</span><span style="background:#373737;color:#c0c0c0">);</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">sort</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">begin</span><span style="background:#373737;color:#c0c0c0">(),</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">end</span><span style="background:#373737;color:#c0c0c0">());</span><span style="background:#373737;color:#c1c0c1">string</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#ffc4e1">&quot;&quot;</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">int</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">for</span><span style="background:#373737;color:#c0c0c0">(; </span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">size</span><span style="background:#373737;color:#c0c0c0">()&amp;&amp;</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">size</span><span style="background:#373737;color:#c0c0c0">();</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">++)</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">if</span><span style="background:#373737;color:#c0c0c0">(</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">]&gt;=</span><span style="background:#373737;color:#ffc4e1">&#39;A&#39;</span><span style="background:#373737;color:#c0c0c0">&amp;&amp;</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">]&lt;=</span><span style="background:#373737;color:#ffc4e1">&#39;Z&#39;</span><span style="background:#373737;color:#c0c0c0">||(</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">]&lt;=</span><span style="background:#373737;color:#ffc4e1">&#39;z&#39;</span><span style="background:#373737;color:#c0c0c0">&amp;&amp;</span><span style="background:#373737;color:#c1c0c1">s</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#9ab40a">0</span><span style="background:#373737;color:#c0c0c0">]&gt;=</span><span style="background:#373737;color:#ffc4e1">&#39;a&#39;</span><span style="background:#373737;color:#c0c0c0">))</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">+</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]+</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">else</span><br> <span style="background:#373737;color:#d24400">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span><span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">=</span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">+</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">]+</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">for</span><span style="background:#373737;color:#c0c0c0">(;</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">size</span><span style="background:#373737;color:#c0c0c0">();</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">++)</span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">+=</span><span style="background:#373737;color:#c1c0c1">SA</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">for</span><span style="background:#373737;color:#c0c0c0">(;</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">&lt;</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">.</span><span style="background:#373737;color:#c1c0c1">size</span><span style="background:#373737;color:#c0c0c0">();</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">++)</span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">+=</span><span style="background:#373737;color:#c1c0c1">SB</span><span style="background:#373737;color:#c0c0c0">[</span><span style="background:#373737;color:#c1c0c1">i</span><span style="background:#373737;color:#c0c0c0">];</span><br> &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0"></span><span style="background:#373737;color:#d24400">return</span><span style="background:#373737;color:#c0c0c0"> </span><span style="background:#373737;color:#c1c0c1">res</span><span style="background:#373737;color:#c0c0c0">;</span><br> &#160;&#160;&#160;&#160;&#160;&#160;<span style="background:#373737;color:#c0c0c0">}</span></div> </div> </div> <p>思路要清晰，两个轮替记录即可</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000pt&nbsp;&nbsp;&nbsp; 显然的BFS 利用队列 只是题意不太好理解，最好把判断写成小函数，主程序会看起来比较清晰，不容易出错~ 一步一步来</p><img src ="http://www.cppblog.com/zqsand/aggbug/104143.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2009-12-26 17:28 <a href="http://www.cppblog.com/zqsand/archive/2009/12/26/104143.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ALGORITHM IN C (1)</title><link>http://www.cppblog.com/zqsand/archive/2009/11/11/100725.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Wed, 11 Nov 2009 12:18:00 GMT</pubDate><guid>http://www.cppblog.com/zqsand/archive/2009/11/11/100725.html</guid><wfw:comment>http://www.cppblog.com/zqsand/comments/100725.html</wfw:comment><comments>http://www.cppblog.com/zqsand/archive/2009/11/11/100725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zqsand/comments/commentRss/100725.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zqsand/services/trackbacks/100725.html</trackback:ping><description><![CDATA[
<pre class="code"><font size="4">Steps to developing a usable algorithm.<br>&#8226; Define the problem.<br>&#8226; Find an algorithm to solve it.<br>&#8226; Fast enough?<br>&#8226; If not, figure out why.<br>&#8226; Find a way to address the problem.<br>&#8226; Iterate until satisfied.</font></pre>
<p><font size="4">&nbsp; </font>
</p><p><font size="4">主要内容 FIND-UNION ALGORITHM </font>
</p><p><font size="4">就是利用并查集来考察连通性的算法 。条件N个节点，M对节点，输入每一对节点时候，如果已经连通，则忽略，否则输出接点并更新 </font>
</p><p><font size="4">主要介绍三种算法：第一种，QUCK-FIND 利用数组记录每一个联通子图，同一个联通子图的节点数组变量是相同的。因此每读入一对就需要遍历N个数组变量考察是否需要更新，最坏时间MN，实际上每个子图为高度为2的树;第二种，QUICK-UNION 联通子图需要union时 仅仅需要将两个root union 因此每个联通子图高度变高，所有find root 会消耗一定时间，当然无需遍历N了 ，最坏时间，也就是每次均需要从叶子节点去回溯求根（这里书中举得例子好像有问题）也是MN；第三种也就是 QUICK WEIGHT UNION 这种方法在两个子树合并的时候，不是简单的指定合并策略，而是经过判断的，把size小（相应高度也小）的合并到size大的里面；实际上很容易理解就是尽量减少树的高度来追求quick-find的效率； </font>
</p><p><font size="4">进而作者写道路径压缩，也是这种思想。或者实现为全部压缩，也就是说在进行union操作的时候，所有check的节点都直接链接到union后的新root下面，或者half union （容易实现且性能好）每次check时候，如果没有停止loop简单的令 id[i]=id[id[i]];即可达到减少到根距离的效果。 </font>
</p><p><font size="4">half union 的主要代码：</font></p><pre class="code"><span style="background: #2b2b2b; color: #0080ff"><font size="4">int </font></span><font size="4"><span style="background: #2b2b2b; color: white">i,j;
</span><span style="background: #2b2b2b; color: #0080ff">for</span></font><font size="4"><span style="background: #2b2b2b; color: white">(i=p;id[i]!=i;i=id[i]) id[i]=id[id[i]];
</span><span style="background: #2b2b2b; color: #0080ff">for</span></font><font size="4"><span style="background: #2b2b2b; color: white">(j=p;id[j]!=j;j=id[j]) id[j]=id[id[j]];
</span><span style="background: #2b2b2b; color: #0080ff">if</span><span style="background: #2b2b2b; color: white">(i==j)</span><span style="background: #2b2b2b; color: #0080ff">continue</span></font><font size="4"><span style="background: #2b2b2b; color: white">;
</span><span style="background: #2b2b2b; color: #0080ff">if</span></font><font size="4"><span style="background: #2b2b2b; color: white">(size[i]&gt;size[j]) id[j]=i,size[i]+=size[j];
</span><span style="background: #2b2b2b; color: #0080ff">else        </span><span style="background: #2b2b2b; color: white">id[i]=j,size[j]+=size[i];</span></font></pre><a href="http://11011.net/software/vspaste"></a>
<p><font size="5"></font>&nbsp; </p><p><font size="5">第一次用windows live writer 试试效果哦~~</font> 
</p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font>&nbsp; </p><p><font size="5"></font></p><img src ="http://www.cppblog.com/zqsand/aggbug/100725.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zqsand/" target="_blank">rikisand</a> 2009-11-11 20:18 <a href="http://www.cppblog.com/zqsand/archive/2009/11/11/100725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>