﻿<?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++博客-Design&amp;Art-随笔分类-C++</title><link>http://www.cppblog.com/abware/category/3994.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 26 Apr 2009 13:07:39 GMT</lastBuildDate><pubDate>Sun, 26 Apr 2009 13:07:39 GMT</pubDate><ttl>60</ttl><item><title>[ZZ]C++中const总结</title><link>http://www.cppblog.com/abware/archive/2009/04/11/79563.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Fri, 10 Apr 2009 16:51:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2009/04/11/79563.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/79563.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2009/04/11/79563.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/79563.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/79563.html</trackback:ping><description><![CDATA[
<div>一、对于基本声明&nbsp;<br><br>1.const&nbsp;int&nbsp;r=100;&nbsp;//标准const变量声明加初始化，因为默认内部连接所以必须被初始化，其作用域为此文件，编译器经过类型检查后直接用100在编译时替换。&nbsp;<br><br>2.extend&nbsp;const&nbsp;int&nbsp;r=100;&nbsp;//将const改为外部连接，作用于扩大至全局，编译时会分配内存，并且可以不进行初始化，仅仅作为声明，编译器认为在程序其他地方进行了定义。&nbsp;<br><br>3.const&nbsp;int&nbsp;r[&nbsp;]={1,2,3,4};&nbsp;<br><br>struct&nbsp;S&nbsp;{int&nbsp;a,b;};&nbsp;<br>const&nbsp;S&nbsp;s[&nbsp;]={(1,2),(3.4)};&nbsp;//以上两种都是常量集合，编译器会为其分配内存，所以不能在编译期间使用其中的值，例如：int&nbsp;temp[r[2]];这样的编译器会报告不能找到常量表达式&nbsp;<br><br>二、对于指针&nbsp;<br>1.const&nbsp;int&nbsp;*r=&amp;x;&nbsp;//声明r为一个指向常量的x的指针，r指向的对象不能被修改，但他可以指向任何地址的常量。&nbsp;<br><br>2.int&nbsp;const&nbsp;*r=&amp;x;&nbsp;//与用法1完全等价，没有任何区别。&nbsp;<br><br>3.int&nbsp;*&nbsp;const&nbsp;r=&amp;x;&nbsp;//声明r为一个常量指针，他指向x，r这个指针的指向不能被修改，但他指向的地址的内容可以修改。&nbsp;<br><br>4.const&nbsp;int&nbsp;*&nbsp;const&nbsp;r=&amp;x;&nbsp;//综合1、3用法，r是一个指向常量的常量型指针。&nbsp;<br><br>三、对于类型检查&nbsp;<br>可以把一个非const对象赋给一个指向const的指针，因为有时候我们不想从这个指针来修改其对象的值；但是不可以把一个const对象赋值给一个非const指针，因为这样可能会通过这个指针改变指向对象的值，但也存在使这种操作通过的合法化写法，使用类型强制转换可以通过指针改变const对象：&nbsp;<br><br>const&nbsp;int&nbsp;r=100;&nbsp;<br>int&nbsp;*&nbsp;ptr&nbsp;=&nbsp;const_cast&lt;int *&gt;(&amp;r);&nbsp;//C++标准，C语言使用：int&nbsp;*&nbsp;ptr&nbsp;=(int*)&amp;r;&nbsp;<br><br>四、对于字符数组&nbsp;<br>如char&nbsp;*&nbsp;name&nbsp;=&nbsp;&#8220;china&#8221;;&nbsp;这样的语句，在编译时是能够通过的，但是&#8221;china&#8221;是常量字符数组，任何想修改他的操作也能通过编译但会引起运行时错误，如果我们想修改字符数组的话就要使用char&nbsp;name[&nbsp;]&nbsp;=&nbsp;&#8220;china&#8221;;&nbsp;这种形式。&nbsp;<br><br>五、对于函数&nbsp;<br>1.void&nbsp;Fuction1&nbsp;(&nbsp;const&nbsp;int&nbsp;r&nbsp;);&nbsp;//此处为参数传递const值，意义是变量初值不能被函数改变&nbsp;<br><br>2.const&nbsp;int&nbsp;Fuction1&nbsp;(int);&nbsp;//此处返回const值，意思指返回的原函数里的变量的初值不能被修改，但是函数按值返回的这个变量被制成副本，能不能被修改就没有了意义，它可以被赋给任何的const或非const类型变量，完全不需要加上这个const关键字。但这只对于内部类型而言（因为内部类型返回的肯定是一个值，而不会返回一个变量，不会作为左值使用），对于用户自定义类型，返回值是常量是非常重要的，见下面条款3。&nbsp;<br><br>3.Class&nbsp;CX;&nbsp;//内部有构造函数，声明如CX(int&nbsp;r&nbsp;=0)&nbsp;<br><br>CX&nbsp;Fuction1&nbsp;()&nbsp;{&nbsp;return&nbsp;CX();&nbsp;}&nbsp;<br><br>const&nbsp;CX&nbsp;Fuction2&nbsp;()&nbsp;{&nbsp;return&nbsp;CX();&nbsp;}&nbsp;<br><br>如有上面的自定义类CX，和函数Fuction1()和Fuction2(),我们进行如下操作时：&nbsp;<br><br>Fuction1()&nbsp;=&nbsp;CX(1);&nbsp;//没有问题，可以作为左值调用&nbsp;<br><br>Fuction2()&nbsp;=&nbsp;CX(1);&nbsp;//编译错误，const返回值禁止作为左值调用。因为左值把返回值作为变量会修改其返回值，const声明禁止这种修改。&nbsp;<br><br><br>4.函数中指针的const传递和返回：&nbsp;<br><br>int&nbsp;F1&nbsp;(const&nbsp;char&nbsp;*&nbsp;pstr);&nbsp;//作为传递的时候使用const修饰可以保证不会通过这个指针来修改传递参数的初值，这里在函数内部任何修改*pstr的企图都会引起编译错误。&nbsp;<br><br>const&nbsp;char&nbsp;*&nbsp;F2&nbsp;();&nbsp;//意义是函数返回的指针指向的对象是一个const对象，它必须赋给一个同样是指向const对象的指针。&nbsp;<br><br>const&nbsp;char&nbsp;*&nbsp;const&nbsp;F3();&nbsp;//比上面多了一个const，这个const的意义只是在他被用作左值时有效，它表明了这个指针除了指向const对象外，它本身也不能被修改，所以就不能当作左值来处理。&nbsp;<br><br><br>5.函数中引用的const传递：&nbsp;<br><br>void&nbsp;F1&nbsp;(&nbsp;const&nbsp;X&amp;&nbsp;px);&nbsp;//这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的，他禁止对引用的对象的一切修改，唯一不同的是按值传递会先建立一个类对象的副本，然后传递过去，而它直接传递地址，所以这种传递比按值传递更有效。&nbsp;<br><br>**另外只有引用的const传递可以传递一个临时对象，因为临时对象都是const属性，且是不可见的，他短时间存在一个局部域中，所以不能使用指针，只有引用的const传递能够捕捉到这个家伙。&nbsp;<br><br>六、对于类&nbsp;<br>1.首先，对于const的成员变量，只能在构造函数里使用初始化成员列表来初始化，试图在构造函数体内进行初始化const成员变量会引起编译错误。初始化成员列表形如：&nbsp;<br>2.X::&nbsp;X&nbsp;(&nbsp;int&nbsp;ir&nbsp;):&nbsp;r(ir)&nbsp;{}&nbsp;//假设r是类X的const成员变量&nbsp;<br><br>2.const成员函数。提到这个概念首先要谈到const对象，正象内置类型能够定义const对象一样（const&nbsp;int&nbsp;r=10;），用户自定义类型也可以定义const对象(const&nbsp;X&nbsp;px(10);)，编译器要保证这个对象在其生命周期内不能够被改变。如果你定义了这样的一个const对象，那么对于这个对象的一切非const成员函数的调用，编译器为了保证对象的const特性，都会禁止并在编译期间报错。所以如果你想让你的成员函数能够在const对象上进行操作的话，就要把这个函数声明为const成员函数。假如f(&nbsp;)是类中的成员函数的话，它的声明形如：&nbsp;<br>int&nbsp;f(&nbsp;)&nbsp;const;&nbsp;//const放在函数的最后，编译器会对这个函数进行检查，在这个函数中的任何试图改变成员变量和调用非const成员函数的操作都被视为非法&nbsp;<br>注意：类的构造和析构函数都不能是const函数。&nbsp;<br><br>3.建立了一个const成员函数，但仍然想用这个函数改变对象内部的数据。这样的一个要求也会经常遇到，尤其是在一个苛刻的面试考官那里。首先我们要弄清楚考官的要求，因为有两种方法可以实现，如果这位考官要求不改变原来类的任何东西，只让你从当前这个const成员函数入手，那么你只有使用前面提到的类型强制转换方法。实例如下：&nbsp;<br><br>//假如有一个叫做X的类，它有一个int成员变量r，我们需要通过一个const成员函数f(&nbsp;)来对这个r进行++r操作，代码如下&nbsp;<br><br>void&nbsp;X::f(&nbsp;)&nbsp;const&nbsp;<br><br>{&nbsp;(const_cast(this))&nbsp;-&gt;&nbsp;++r;&nbsp;}&nbsp;//通过this指针进行类型强制转换实现&nbsp;<br><br>另外一种方法就是使用关键字：mutable。如果你的成员变量在定义时是这个样子的：&nbsp;<br><br>mutable&nbsp;int&nbsp;r&nbsp;;&nbsp;<br><br>那么它就告诉编译器这个成员变量可以通过const成员函数改变。编译器就不会再理会对他的检查了。&nbsp;</div><img src ="http://www.cppblog.com/abware/aggbug/79563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2009-04-11 00:51 <a href="http://www.cppblog.com/abware/archive/2009/04/11/79563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static</title><link>http://www.cppblog.com/abware/archive/2007/11/21/37053.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Tue, 20 Nov 2007 17:10:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/11/21/37053.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/37053.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/11/21/37053.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/37053.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/37053.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: C++的static有两种用法：面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数，不涉及类；后者主要说明static在类中的作用。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/abware/archive/2007/11/21/37053.html'>阅读全文</a><img src ="http://www.cppblog.com/abware/aggbug/37053.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-11-21 01:10 <a href="http://www.cppblog.com/abware/archive/2007/11/21/37053.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一小段代码</title><link>http://www.cppblog.com/abware/archive/2007/11/09/36249.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Fri, 09 Nov 2007 12:00:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/11/09/36249.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/36249.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/11/09/36249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/36249.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/36249.html</trackback:ping><description><![CDATA[在网上看到这样一小段有意思的代码：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;a[</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;=</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[i]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,a[i]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
这段代码里的错误很明显，数组a在循环时越界了。不过在VC6下编译运行后的结果很有意思，是个无限循环，知道为什么吗？
<img src ="http://www.cppblog.com/abware/aggbug/36249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-11-09 20:00 <a href="http://www.cppblog.com/abware/archive/2007/11/09/36249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TinyXml中文文档</title><link>http://www.cppblog.com/abware/archive/2007/09/26/32920.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Wed, 26 Sep 2007 08:43:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/09/26/32920.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/32920.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/09/26/32920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/32920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/32920.html</trackback:ping><description><![CDATA[TinyXml是一个C++的，<span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 10.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">简单小巧，支持</span><span lang=EN-US style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-size: 10.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">STL</span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 10.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">，而且跨平台的XML解析器。</span><a href="http://www.hansencode.cn/category/tinyxml/"><br>http://www.hansencode.cn/category/tinyxml/</a>
<img src ="http://www.cppblog.com/abware/aggbug/32920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-09-26 16:43 <a href="http://www.cppblog.com/abware/archive/2007/09/26/32920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>双分派(double dispatch)</title><link>http://www.cppblog.com/abware/archive/2007/09/19/32482.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Wed, 19 Sep 2007 08:18:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/09/19/32482.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/32482.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/09/19/32482.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/32482.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/32482.html</trackback:ping><description><![CDATA[一. 定义<br>双分派是指：接受者和参数都能在运行时决定它的类型。(从而若有同名函数的话,依参数选定目标函数)<br><br>二. 问题的提出<br>C++ 不支持双分派，只支持单分派。也就是说参数的类型将在编译阶段决定。(虽然遇上同名函数的选取时，没有体现多态，但进入函数后，指针参数或引用参数仍然表现了其多态)<br>下面的代码演示了该问题：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><span style="COLOR: #000000" twffan="done">#include&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;</span><span style="COLOR: #000000" twffan="done">iostream</span><span style="COLOR: #000000" twffan="done">&gt;</span><span style="COLOR: #000000" twffan="done"><br></span><span style="COLOR: #0000ff" twffan="done">using</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #0000ff" twffan="done">namespace</span><span style="COLOR: #000000" twffan="done">&nbsp;std;<br><br></span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">&nbsp;D;<br><br></span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done">B</span><span style="COLOR: #008000" twffan="done"><br></span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">&nbsp;B<br>{<br></span><span style="COLOR: #0000ff" twffan="done">public</span><span style="COLOR: #000000" twffan="done">:<br>&nbsp;</span><span style="COLOR: #0000ff" twffan="done">void</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #0000ff" twffan="done">virtual</span><span style="COLOR: #000000" twffan="done">&nbsp;output(B&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;b){cout&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">B:B</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;endl;}<br>&nbsp;</span><span style="COLOR: #0000ff" twffan="done">void</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #0000ff" twffan="done">virtual</span><span style="COLOR: #000000" twffan="done">&nbsp;output(D&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;d){cout&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">B:D</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;endl;}<br>};<br></span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">&nbsp;D&nbsp;:&nbsp;</span><span style="COLOR: #0000ff" twffan="done">public</span><span style="COLOR: #000000" twffan="done">&nbsp;B<br>{<br></span><span style="COLOR: #0000ff" twffan="done">public</span><span style="COLOR: #000000" twffan="done">:<br>&nbsp;</span><span style="COLOR: #0000ff" twffan="done">void</span><span style="COLOR: #000000" twffan="done">&nbsp;output(B&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;b){cout&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">D:B</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;endl;}<br>&nbsp;</span><span style="COLOR: #0000ff" twffan="done">void</span><span style="COLOR: #000000" twffan="done">&nbsp;output(D&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;d){cout&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">D:D</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">&lt;&lt;</span><span style="COLOR: #000000" twffan="done">&nbsp;endl;}<br>};<br><br></span><span style="COLOR: #0000ff" twffan="done">int</span><span style="COLOR: #000000" twffan="done">&nbsp;main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;B&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;p1&nbsp;</span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #0000ff" twffan="done">new</span><span style="COLOR: #000000" twffan="done">&nbsp;D;<br>&nbsp;&nbsp;&nbsp;&nbsp;B&nbsp;</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">&nbsp;p2&nbsp;</span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #0000ff" twffan="done">new</span><span style="COLOR: #000000" twffan="done">&nbsp;D;<br>&nbsp;&nbsp;&nbsp;&nbsp;p1</span><span style="COLOR: #000000" twffan="done">-&gt;</span><span style="COLOR: #000000" twffan="done">output(p2);<br>&nbsp;<br>&nbsp;</span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done">&nbsp;</span><span style="COLOR: #000000" twffan="done">0</span><span style="COLOR: #000000" twffan="done">;<br>}<br></span></div>
以上代码的输出结果是：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top twffan="done"><span style="COLOR: #000000" twffan="done">D:B</span></div>
如果参数能够在运行时决定类型的话，那么输出来的信息应该是D:D，因为p2的实际类型是D。但是，事实上输出来的结果是D:B。也就是说p2的类型被误解为B了！这就是问题的所在。<br><br>三. 解决方法<br>Visitor设计模式
<img src ="http://www.cppblog.com/abware/aggbug/32482.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-09-19 16:18 <a href="http://www.cppblog.com/abware/archive/2007/09/19/32482.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>typename</title><link>http://www.cppblog.com/abware/archive/2007/04/16/22020.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Mon, 16 Apr 2007 07:27:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/04/16/22020.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/22020.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/04/16/22020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/22020.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/22020.html</trackback:ping><description><![CDATA[<h1>(zz) C++箴言：理解typename的两个含义</h1>
　　问题：在下面的 template declarations（模板声明）中 class 和 typename 有什么不同？
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Widget;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;uses&nbsp;"class"</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Widget;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;uses&nbsp;"typename"</span></div>
　　答案：没什么不同。在声明一个 template type parameter（模板类型参数）的时候，class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class，因为它更容易输入。其他人（包括我本人）更喜欢 typename，因为它暗示着这个参数不必要是一个 class type（类类型）。少数开发者在任何类型都被允许的时候使用 typename，而把 class 保留给仅接受 user-defined types（用户定义类型）的场合。但是从 C++ 的观点看，class 和 typename 在声明一个 template parameter（模板参数）时意味着完全相同的东西。<br><br>　　然而，C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点，我们不得不讨论你会在一个 template（模板）中涉及到的两种名字。<br><br>　　假设我们有一个函数的模板，它能取得一个 STL-compatible container（STL 兼容容器）中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数，而且就像我下面写的，它甚至不能编译，但是请将这些事先放在一边——有一种方法能发现我的愚蠢：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;print&nbsp;2nd&nbsp;element&nbsp;in</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print2nd(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;C</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;container)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;container;</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_93_361_Open_Image onclick="this.style.display='none'; Codehighlighter1_93_361_Open_Text.style.display='none'; Codehighlighter1_93_361_Closed_Image.style.display='inline'; Codehighlighter1_93_361_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_93_361_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_93_361_Closed_Text.style.display='none'; Codehighlighter1_93_361_Open_Image.style.display='inline'; Codehighlighter1_93_361_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_93_361_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_93_361_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;this&nbsp;is&nbsp;not&nbsp;valid&nbsp;C++!</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_151_359_Open_Image onclick="this.style.display='none'; Codehighlighter1_151_359_Open_Text.style.display='none'; Codehighlighter1_151_359_Closed_Image.style.display='inline'; Codehighlighter1_151_359_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_151_359_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_151_359_Closed_Text.style.display='none'; Codehighlighter1_151_359_Open_Image.style.display='inline'; Codehighlighter1_151_359_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(container.size()&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)&nbsp;</span><span id=Codehighlighter1_151_359_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_151_359_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　　C::const_iterator&nbsp;iter(container.begin());&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;get&nbsp;iterator&nbsp;to&nbsp;1st&nbsp;element</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">　　</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">iter;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;move&nbsp;iter&nbsp;to&nbsp;2nd&nbsp;element</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">　　</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;value&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">iter;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;copy&nbsp;that&nbsp;element&nbsp;to&nbsp;an&nbsp;int</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">　　std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;value;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;print&nbsp;the&nbsp;int</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top></span><span style="COLOR: #000000">　}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
　　我突出了这个函数中的两个 local variables（局部变量），iter 和 value。iter 的类型是 C::const_iterator，一个依赖于 template parameter（模板参数）C 的类型。一个 template（模板）中的依赖于一个 template parameter（模板参数）的名字被称为 dependent names（依赖名字）。当一个 dependent names（依赖名字）嵌套在一个 class（类）的内部时，我称它为 nested dependent name（嵌套依赖名字）。C::const_iterator 是一个 nested dependent name（嵌套依赖名字）。实际上，它是一个 nested dependent type name（嵌套依赖类型名），也就是说，一个涉及到一个 type（类型）的 nested dependent name（嵌套依赖名字）。<br><br>　　print2nd 中的另一个 local variable（局部变量）value 具有 int 类型。int 是一个不依赖于任何 template parameter（模板参数）的名字。这样的名字以 non-dependent names（非依赖名字）闻名。（我想不通为什么他们不称它为 independent names（无依赖名字）。如果，像我一样，你发现术语 "non-dependent" 是一个令人厌恶的东西，你就和我产生了共鸣，但是 "non-dependent" 就是这类名字的术语，所以，像我一样，转转眼睛放弃你的自我主张。）<br><br>　　nested dependent name（嵌套依赖名字）会导致解析困难。例如，假设我们更加愚蠢地以这种方法开始 print2nd：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print2nd(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;C</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;container)<br><img id=Codehighlighter1_55_88_Open_Image onclick="this.style.display='none'; Codehighlighter1_55_88_Open_Text.style.display='none'; Codehighlighter1_55_88_Closed_Image.style.display='inline'; Codehighlighter1_55_88_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_55_88_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_55_88_Closed_Text.style.display='none'; Codehighlighter1_55_88_Open_Image.style.display='inline'; Codehighlighter1_55_88_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_55_88_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_55_88_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　C::const_iterator&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;x;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span></div>
　　这看上去好像是我们将 x 声明为一个指向 C::const_iterator 的 local variable（局部变量）。但是它看上去如此仅仅是因为我们知道 C::const_iterator 是一个 type（类型）。但是如果 C::const_iterator 不是一个 type（类型）呢？如果 C 有一个 static data member（静态数据成员）碰巧就叫做 const_iterator 呢？再如果 x 碰巧是一个 global variable（全局变量）的名字呢？在这种情况下，上面的代码就不是声明一个 local variable（局部变量），而是成为 C::const_iterator 乘以 x！当然，这听起来有些愚蠢，但它是可能的，而编写 C++ 解析器的人必须考虑所有可能的输入，甚至是愚蠢的。<br><br>　　直到 C 成为已知之前，没有任何办法知道 C::const_iterator 到底是不是一个 type（类型），而当 template（模板）print2nd 被解析的时候，C 还不是已知的。C++ 有一条规则解决这个歧义：如果解析器在一个 template（模板）中遇到一个 nested dependent name（嵌套依赖名字），它假定那个名字不是一个 type（类型），除非你用其它方式告诉它。缺省情况下，nested dependent name（嵌套依赖名字）不是 types（类型）。（对于这条规则有一个例外，我待会儿告诉你。）<br><br>　　记住这个，再看看 print2nd 的开头：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print2nd(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;C</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;container)<br>{<br>　</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(container.size()&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)&nbsp;{<br>　　C::const_iterator&nbsp;iter(container.begin());&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;this&nbsp;name&nbsp;is&nbsp;assumed&nbsp;to</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;not&nbsp;be&nbsp;a&nbsp;type</span></div>
　　这为什么不是合法的 C++ 现在应该很清楚了。iter 的 declaration（声明）仅仅在 C::const_iterator 是一个 type（类型）时才有意义，但是我们没有告诉 C++ 它是，而 C++ 就假定它不是。要想转变这个形势，我们必须告诉 C++ C::const_iterator 是一个 type（类型）。我们将 typename 放在紧挨着它的前面来做到这一点：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;this&nbsp;is&nbsp;valid&nbsp;C++</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print2nd(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;C</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;container)<br>{<br></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(container.size()&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)&nbsp;{<br>typename&nbsp;C::const_iterator&nbsp;iter(container.begin());<br><img src="http://www.cppblog.com/Images/dot.gif"><br>}<br>}</span></div>
　　通用的规则很简单：在你涉及到一个在 template（模板）中的 nested dependent type name（嵌套依赖类型名）的任何时候，你必须把单词 typename 放在紧挨着它的前面。（重申一下，我待会儿要描述一个例外。）<br><br>　　typename 应该仅仅被用于标识 nested dependent type name（嵌套依赖类型名）；其它名字不应该用它。例如，这是一个取得一个 container（容器）和这个 container（容器）中的一个 iterator（迭代器）的 function template（函数模板）：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;C</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;typename&nbsp;allowed&nbsp;(as&nbsp;is&nbsp;"class")</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;f(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;C</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;container,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;typename&nbsp;not&nbsp;allowed</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">typename&nbsp;C::iterator&nbsp;iter);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;typename&nbsp;required</span></div>
　　C 不是一个 nested dependent type name（嵌套依赖类型名）（它不是嵌套在依赖于一个 template parameter（模板参数）的什么东西内部的），所以在声明 container 时它不必被 typename 前置，但是 C::iterator 是一个 nested dependent type name（嵌套依赖类型名），所以它必需被 typename 前置。<br><br>　　"typename must precede nested dependent type names"（&#8220;typename 必须前置于嵌套依赖类型名&#8221;）规则的例外是 typename 不必前置于在一个 list of base classes（基类列表）中的或者在一个 member initialization list（成员初始化列表）中作为一个 base classes identifier（基类标识符）的 nested dependent type name（嵌套依赖类型名）。例如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Derived:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;Base</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::Nested&nbsp;{&nbsp;<br>　</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;base&nbsp;class&nbsp;list:&nbsp;typename&nbsp;not</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;allowed</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;Derived(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;x)<br>　　:&nbsp;Base</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::Nested(x)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;base&nbsp;class&nbsp;identifier&nbsp;in&nbsp;mem</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　{&nbsp;<br>　　　</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;init.&nbsp;list:&nbsp;typename&nbsp;not&nbsp;allowed</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　<br>　　　typename&nbsp;Base</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::Nested&nbsp;temp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;use&nbsp;of&nbsp;nested&nbsp;dependent&nbsp;type</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　　<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;name&nbsp;not&nbsp;in&nbsp;a&nbsp;base&nbsp;class&nbsp;list&nbsp;or</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　}&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;as&nbsp;a&nbsp;base&nbsp;class&nbsp;identifier&nbsp;in&nbsp;a</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">　　<img src="http://www.cppblog.com/Images/dot.gif">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;mem.&nbsp;init.&nbsp;list:&nbsp;typename&nbsp;required</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">};</span></div>
　　这样的矛盾很令人讨厌，但是一旦你在经历中获得一点经验，你几乎不会在意它。<br><br>　　让我们来看最后一个 typename 的例子，因为它在你看到的真实代码中具有代表性。假设我们在写一个取得一个 iterator（迭代器）的 function template（函数模板），而且我们要做一个 iterator（迭代器）指向的 object（对象）的局部拷贝 temp，我们可以这样做：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;IterT</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;workWithIterator(IterT&nbsp;iter)<br><img id=Codehighlighter1_59_129_Open_Image onclick="this.style.display='none'; Codehighlighter1_59_129_Open_Text.style.display='none'; Codehighlighter1_59_129_Closed_Image.style.display='inline'; Codehighlighter1_59_129_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_59_129_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_59_129_Closed_Text.style.display='none'; Codehighlighter1_59_129_Open_Image.style.display='inline'; Codehighlighter1_59_129_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_59_129_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_59_129_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　typename&nbsp;std::iterator_traits</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">IterT</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::value_type&nbsp;temp(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">iter);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
　　不要让 std::iterator_traits&lt;IterT&gt;::value_type 吓倒你。那仅仅是一个 standard traits class（标准特性类）的使用，用 C++ 的说法就是 "the type of thing pointed to by objects of type IterT"（&#8220;被类型为 IterT 的对象所指向的东西的类型&#8221;）。这个语句声明了一个与 IterT objects 所指向的东西类型相同的 local variable（局部变量）(temp)，而且用 iter 所指向的 object（对象）对 temp 进行了初始化。如果 IterT 是 vector&lt;int&gt;::iterator，temp 就是 int 类型。如果 IterT 是 list&lt;string&gt;::iterator，temp 就是 string 类型。因为 std::iterator_traits&lt;IterT&gt;::value_type 是一个 nested dependent type name（嵌套依赖类型名）（value_type 嵌套在 iterator_traits&lt;IterT&gt; 内部，而且 IterT 是一个 template parameter（模板参数）），我们必须让它被 typename 前置。<br><br>　　如果你觉得读 std::iterator_traits&lt;IterT&gt;::value_type 令人讨厌，就想象那个与它相同的东西来代表它。如果你像大多数程序员，对多次输入它感到恐惧，那么你就需要创建一个 typedef。对于像 value_type 这样的 traits member names（特性成员名），一个通用的惯例是 typedef name 与 traits member name 相同，所以这样的一个 local typedef 通常定义成这样：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;IterT</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;workWithIterator(IterT&nbsp;iter)<br><img id=Codehighlighter1_59_162_Open_Image onclick="this.style.display='none'; Codehighlighter1_59_162_Open_Text.style.display='none'; Codehighlighter1_59_162_Closed_Image.style.display='inline'; Codehighlighter1_59_162_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_59_162_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_59_162_Closed_Text.style.display='none'; Codehighlighter1_59_162_Open_Image.style.display='inline'; Codehighlighter1_59_162_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_59_162_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_59_162_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　typedef&nbsp;typename&nbsp;std::iterator_traits</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">IterT</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::value_type&nbsp;value_type;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　value_type&nbsp;temp(</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">iter);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>　<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
　　很多程序员最初发现 "typedef typename" 并列不太和谐，但它是涉及 nested dependent type names（嵌套依赖类型名）规则的一个合理的附带结果。你会相当快地习惯它。你毕竟有着强大的动机。你输入 typename std::iterator_traits&lt;IterT&gt;::value_type 需要多少时间？<br><br>　　作为结束语，我应该提及编译器与编译器之间对围绕 typename 的规则的执行情况的不同。一些编译器接受必需 typename 时它却缺失的代码；一些编译器接受不许 typename 时它却存在的代码；还有少数的（通常是老旧的）会拒绝 typename 出现在它必需出现的地方。这就意味着 typename 和 nested dependent type names（嵌套依赖类型名）的交互作用会导致一些轻微的可移植性问题。<br><br>　　Things to Remember<br><br>　　&#183;在声明 template parameters（模板参数）时，class 和 typename 是可互换的。<br><br>　　&#183;用 typename 去标识 nested dependent type names（嵌套依赖类型名），在 base class lists（基类列表）中或在一个 member initialization list（成员初始化列表）中作为一个 base class identifier（基类标识符）时除外。<br><br>
<img src ="http://www.cppblog.com/abware/aggbug/22020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-04-16 15:27 <a href="http://www.cppblog.com/abware/archive/2007/04/16/22020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>explicit</title><link>http://www.cppblog.com/abware/archive/2007/04/12/21691.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Thu, 12 Apr 2007 03:09:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/04/12/21691.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/21691.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/04/12/21691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/21691.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/21691.html</trackback:ping><description><![CDATA[<p>我们在编写应用程序的时候explicit关键字基本上是很少使用,它的作用是"禁止单参数构造函数"被用于自动型别转换,其中比较典型的例子就是容器类型,在这种类型的构造函数中你可以将初始长度作为参数传递给构造函数.<br>例如:<br>你可以声明这样一个构造函数</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Array<br><img id=Codehighlighter1_12_59_Open_Image onclick="this.style.display='none'; Codehighlighter1_12_59_Open_Text.style.display='none'; Codehighlighter1_12_59_Closed_Image.style.display='inline'; Codehighlighter1_12_59_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_12_59_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_12_59_Closed_Text.style.display='none'; Codehighlighter1_12_59_Open_Image.style.display='inline'; Codehighlighter1_12_59_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_12_59_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_12_59_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;Array(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;size);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">;</span></div>
在这里explicit关键字起着至关重要的作用,如果没有这个关键字的话,这个构造函数有能力将int转换成Array.一旦这种情况发生,你可以给Array支派一个整数值而不会引起任何的问题,比如:
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">Array&nbsp;arr;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">arr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">40</span><span style="COLOR: #000000">;</span></div>
此时,C++的自动型别转换会把40转换成拥有40个元素的Array,并且指派给arr变量,这个结果根本就不是我们想要的结果.如果我们将构造函数声明为explicit,上面的赋值操作就会导致编译器报错,使我们可以及时发现错误.<br>需要注意的是:explicit同样也能阻止"以赋值语法进行带有转型操作的初始化";<br>例如:
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">Array&nbsp;arr(</span><span style="COLOR: #000000">40</span><span style="COLOR: #000000">);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">正确</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">Array&nbsp;arr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">40</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">错误&nbsp;</span></div>
看一下以下两种操作:
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">X&nbsp;x;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Y&nbsp;y(x);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">显式类型转换</span></div>
另一种
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">X&nbsp;x;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Y&nbsp;y&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;x;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">隐式类型转换</span></div>
这两种操作存在一个小小的差别,第一种方式式通过显式类型转换,根据型别x产生了型别Y的新对象;第二种方式通过隐式转换产生了一个型别Y的新对象.<br>explicit关键字的应用主要就是上面所说的构造函数定义中,参考该关键字的应用可以看看STL源代码,其中大量使用了该关键字 
<img src ="http://www.cppblog.com/abware/aggbug/21691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-04-12 11:09 <a href="http://www.cppblog.com/abware/archive/2007/04/12/21691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mutable</title><link>http://www.cppblog.com/abware/archive/2007/04/12/21687.html</link><dc:creator>安帛伟</dc:creator><author>安帛伟</author><pubDate>Thu, 12 Apr 2007 02:50:00 GMT</pubDate><guid>http://www.cppblog.com/abware/archive/2007/04/12/21687.html</guid><wfw:comment>http://www.cppblog.com/abware/comments/21687.html</wfw:comment><comments>http://www.cppblog.com/abware/archive/2007/04/12/21687.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/abware/comments/commentRss/21687.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/abware/services/trackbacks/21687.html</trackback:ping><description><![CDATA[<p>关键字mutable是C++中一个不常用的关键字,他只能用于类的非静态和非常量数据成员<br>我们知道一个对象的状态由该对象的非静态数据成员决定,所以随着数据成员的改变,<br>对像的状态也会随之发生变化! <br>如果一个类的成员函数被声明为const类型,表示该函数不会改变对象的状态,也就是<br>该函数不会修改类的非静态数据成员.但是有些时候需要在该类函数中对类的数据成员<br>进行赋值.这个时候就需要用到mutable关键字了 </p>
<p>例如:<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Demo<br><img id=Codehighlighter1_11_185_Open_Image onclick="this.style.display='none'; Codehighlighter1_11_185_Open_Text.style.display='none'; Codehighlighter1_11_185_Closed_Image.style.display='inline'; Codehighlighter1_11_185_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_11_185_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_11_185_Closed_Text.style.display='none'; Codehighlighter1_11_185_Open_Image.style.display='inline'; Codehighlighter1_11_185_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_11_185_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_11_185_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_31_32_Open_Image onclick="this.style.display='none'; Codehighlighter1_31_32_Open_Text.style.display='none'; Codehighlighter1_31_32_Closed_Image.style.display='inline'; Codehighlighter1_31_32_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_31_32_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_32_Closed_Text.style.display='none'; Codehighlighter1_31_32_Open_Image.style.display='inline'; Codehighlighter1_31_32_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Demo()</span><span id=Codehighlighter1_31_32_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_31_32_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_45_46_Open_Image onclick="this.style.display='none'; Codehighlighter1_45_46_Open_Text.style.display='none'; Codehighlighter1_45_46_Closed_Image.style.display='inline'; Codehighlighter1_45_46_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_45_46_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_45_46_Closed_Text.style.display='none'; Codehighlighter1_45_46_Open_Image.style.display='inline'; Codehighlighter1_45_46_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Demo()</span><span id=Codehighlighter1_45_46_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_45_46_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;getFlag()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_85_136_Open_Image onclick="this.style.display='none'; Codehighlighter1_85_136_Open_Text.style.display='none'; Codehighlighter1_85_136_Closed_Image.style.display='inline'; Codehighlighter1_85_136_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_85_136_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_85_136_Closed_Text.style.display='none'; Codehighlighter1_85_136_Open_Image.style.display='inline'; Codehighlighter1_85_136_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_85_136_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_85_136_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_nAccess</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;m_bFlag;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;m_nAccess;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;m_bFlag;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_201_217_Open_Image onclick="this.style.display='none'; Codehighlighter1_201_217_Open_Text.style.display='none'; Codehighlighter1_201_217_Closed_Image.style.display='inline'; Codehighlighter1_201_217_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_201_217_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_201_217_Closed_Text.style.display='none'; Codehighlighter1_201_217_Open_Image.style.display='inline'; Codehighlighter1_201_217_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_201_217_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_201_217_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;</span></div>
<p><br>编译上面的代码会出现 error C2166: l-value specifies const object的错误<br>说明在const类型的函数中改变了类的非静态数据成员. </p>
<p>这个时候需要使用mutable来修饰一下要在const成员函数中改变的非静态数据成员<br>m_nAccess,代码如下: <br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Demo<br><img id=Codehighlighter1_11_193_Open_Image onclick="this.style.display='none'; Codehighlighter1_11_193_Open_Text.style.display='none'; Codehighlighter1_11_193_Closed_Image.style.display='inline'; Codehighlighter1_11_193_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_11_193_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_11_193_Closed_Text.style.display='none'; Codehighlighter1_11_193_Open_Image.style.display='inline'; Codehighlighter1_11_193_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_11_193_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_11_193_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_31_32_Open_Image onclick="this.style.display='none'; Codehighlighter1_31_32_Open_Text.style.display='none'; Codehighlighter1_31_32_Closed_Image.style.display='inline'; Codehighlighter1_31_32_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_31_32_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_32_Closed_Text.style.display='none'; Codehighlighter1_31_32_Open_Image.style.display='inline'; Codehighlighter1_31_32_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Demo()</span><span id=Codehighlighter1_31_32_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_31_32_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_45_46_Open_Image onclick="this.style.display='none'; Codehighlighter1_45_46_Open_Text.style.display='none'; Codehighlighter1_45_46_Closed_Image.style.display='inline'; Codehighlighter1_45_46_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_45_46_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_45_46_Closed_Text.style.display='none'; Codehighlighter1_45_46_Open_Image.style.display='inline'; Codehighlighter1_45_46_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Demo()</span><span id=Codehighlighter1_45_46_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_45_46_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;getFlag()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_85_136_Open_Image onclick="this.style.display='none'; Codehighlighter1_85_136_Open_Text.style.display='none'; Codehighlighter1_85_136_Closed_Image.style.display='inline'; Codehighlighter1_85_136_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_85_136_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_85_136_Closed_Text.style.display='none'; Codehighlighter1_85_136_Open_Image.style.display='inline'; Codehighlighter1_85_136_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_85_136_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_85_136_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_nAccess</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;m_bFlag;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;m_nAccess;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;m_bFlag;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_209_225_Open_Image onclick="this.style.display='none'; Codehighlighter1_209_225_Open_Text.style.display='none'; Codehighlighter1_209_225_Closed_Image.style.display='inline'; Codehighlighter1_209_225_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_209_225_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_209_225_Closed_Text.style.display='none'; Codehighlighter1_209_225_Open_Image.style.display='inline'; Codehighlighter1_209_225_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_209_225_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_209_225_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;</span></div>
<br>这样再重新编译的时候就不会出现错误了!<br>
<img src ="http://www.cppblog.com/abware/aggbug/21687.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/abware/" target="_blank">安帛伟</a> 2007-04-12 10:50 <a href="http://www.cppblog.com/abware/archive/2007/04/12/21687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>