﻿<?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++</title><link>http://www.cppblog.com/TinYShoW/category/18487.html</link><description>别让暂时的闲适消磨自己的斗志...加油</description><language>zh-cn</language><lastBuildDate>Fri, 21 Dec 2012 18:48:40 GMT</lastBuildDate><pubDate>Fri, 21 Dec 2012 18:48:40 GMT</pubDate><ttl>60</ttl><item><title>const</title><link>http://www.cppblog.com/TinYShoW/articles/195275.html</link><dc:creator>HiHi..!</dc:creator><author>HiHi..!</author><pubDate>Fri, 16 Nov 2012 08:28:00 GMT</pubDate><guid>http://www.cppblog.com/TinYShoW/articles/195275.html</guid><wfw:comment>http://www.cppblog.com/TinYShoW/comments/195275.html</wfw:comment><comments>http://www.cppblog.com/TinYShoW/articles/195275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/TinYShoW/comments/commentRss/195275.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/TinYShoW/services/trackbacks/195275.html</trackback:ping><description><![CDATA[<p><span style="font-size: 12pt">C++常类型(const)&#8212;&#8212;Use const whenever you need</span><br /><span style="font-size: 12pt">常类型是指使用类型修饰符const说明的类型，常类型的变量或对象的值是不能被更新的。因此，定义或说明常类型时必须进行初始化。</span><br /><span style="font-size: 12pt">一般常量和对象常量 </span><br /><span style="font-size: 12pt">　　1. 一般常量</span><br /><span style="font-size: 12pt">　　一般常量是指简单类型的常量。这种常量在定义时，修饰符const可以用在类型说明符前，也可以用在类型说明符后。如：</span><br /><span style="font-size: 12pt">　　int const x=2;</span><br /><span style="font-size: 12pt">　　或</span><br /><span style="font-size: 12pt">　　const int x=2;</span><br /><span style="font-size: 12pt">　　定义或说明一个常数组可采用如下格式：</span><br /><span style="font-size: 12pt">　　&lt;类型说明符&gt; const &lt;数组名&gt;[&lt;大小&gt;]&#8230;</span><br /><span style="font-size: 12pt">　　或者</span><br /><span style="font-size: 12pt">　　const &lt;类型说明符&gt; &lt;数组名&gt;[&lt;大小&gt;]&#8230;</span><br /><span style="font-size: 12pt">　　例如：</span><br /><span style="font-size: 12pt">　　int const a[5]={1, 2, 3, 4, 5};</span><br /><span style="font-size: 12pt">　　2. 常对象</span><br /><span style="font-size: 12pt">　　常对象是指对象常量，定义格式如下：</span><br /><span style="font-size: 12pt">　　&lt;类名&gt; const &lt;对象名&gt;</span><br /><span style="font-size: 12pt">　　或者</span><br /><span style="font-size: 12pt">　　const &lt;类名&gt; &lt;对象名&gt;</span><br /><span style="font-size: 12pt">　　定义常对象时，同样要进行初始化，并且该对象不能再被更新，修饰符const可以放在类名后面，也可以放在类名前面。</span><br /><span style="font-size: 12pt">常指针和常引用 </span><br /><span style="font-size: 12pt">　　1. 常指针</span><br /><span style="font-size: 12pt">　　使用const修饰指针时，由于const的位置不同，而含意不同。下面举两个例子，说明它们的区别。</span><br /><span style="font-size: 12pt">　　下面定义的一个指向字符串的常量指针：</span><br /><span style="font-size: 12pt">　　char * const prt1 = stringprt1;</span><br /><span style="font-size: 12pt">　　其中，ptr1是一个常量指针。因此，下面赋值是非法的。</span><br /><span style="font-size: 12pt">　　ptr1 = stringprt2;</span><br /><span style="font-size: 12pt">　　而下面的赋值是合法的：</span><br /><span style="font-size: 12pt">　　*ptr1 = "m";</span><br /><span style="font-size: 12pt">　　因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。</span><br /><span style="font-size: 12pt">　　下面定义了一个指向字符串常量的指针：</span><br /><span style="font-size: 12pt">　　const char * ptr2 = stringprt1;</span><br /><span style="font-size: 12pt">　　其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此，</span><br /><span style="font-size: 12pt">　　*ptr2 = "x";</span><br /><span style="font-size: 12pt">　　是非法的，而：</span><br /><span style="font-size: 12pt">　　ptr2 = stringptr2;</span><br /><span style="font-size: 12pt">　　是合法的。</span><br /><span style="font-size: 12pt">　　所以，在使用const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同。</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指向字符串的指针常量&#8212;&#8212;const放在*后</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指向字符串常量的指针&#8212;&#8212;const放在*前。</span><br /><span style="font-size: 12pt">　　2. 常引用</span><br /><span style="font-size: 12pt">　　使用const修饰符也可以说明引用，被说明的引用为常引用，该引用所引用的对象不能被更新。其定义格式如下：</span><br /><span style="font-size: 12pt">　　const &lt;类型说明符&gt; &amp; &lt;引用名&gt;</span><br /><span style="font-size: 12pt">　　例如：</span><br /><span style="font-size: 12pt">　　const double &amp; v;</span><br /><span style="font-size: 12pt">　　在实际应用中，常指针和常引用往往用来作函数的形参，这样的参数称为常参数。</span><br /><span style="font-size: 12pt">在C++面向对象的程序设计中，指针和引用使用得较多，其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象，这样，在参数传递过程中就不需要执行拷贝初始化构造函数，这将会改善程序的运行效率。</span><br /><span style="font-size: 12pt">常成员函数 </span><br /><span style="font-size: 12pt">　　使用const关键字进行说明的成员函数，称为常成员函数。只有常成员函数才有资格操作常量或常对象，没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下：</span><br /><span style="font-size: 12pt">　　&lt;类型说明符&gt; &lt;函数名&gt; (&lt;参数表&gt;) const；</span><br /><span style="font-size: 12pt">其中，const是加在函数说明后面的类型修饰符，它是函数类型的一个组成部分，因此，在函数实现部分也要带const关键字。</span><br /><span style="font-size: 12pt">常数据成员 </span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型修饰符const不仅可以说明成员函数，也可以说明数据成员。</span><br /><span style="font-size: 12pt">　　由于const类型对象必须被初始化，并且不能更新，因此，在类中说明了const数据成员时，只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。</span><br /><span style="font-size: 12pt">===============================================================================================</span><br /><span style="font-size: 12pt">用途</span><br /><span style="font-size: 12pt">1、用const修饰函数的参数</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 对于非内部数据类型的输入参数，应该将&#8220;值传递&#8221;的方式改为&#8220;const引用传递&#8221;，目的是提高效率.例如将void Func(A a) 改为void Func(const A &amp;a)；</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 对于内部数据类型的输入参数，不要将&#8220;值传递&#8221;的方式改为&#8220;const引用传递&#8221;.否则既达不到提高效率的目的，又降低了函数的可理解性。</span><br /><span style="font-size: 12pt">2、用const修饰函数的返回值 </span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 如果函数返回值采用&#8220;值传递方式&#8221;，由于函数会把返回值复制到外部临时的存储单元中，加const修饰没有任何价值</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 如果给以&#8220;指针传递&#8221;方式的函数返回值加const修饰，那么函数返回值(即指针)的内容不能被修改，该返回值只能被赋给加const修饰的同类型指针</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 函数返回值采用&#8220;引用传递&#8221;的场合并不多，这种方式一般只出现在类的赋值函数中，目的是为了实现链式表达</span><br /><span style="font-size: 12pt">3、const成员函数</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp; 任何不会修改数据成员的函数都应该声明为const类型.如果在编写const成员函数时，不慎修改了数据成员，或者调用了其它非const成员函数，编译器将指出错误，这无疑会提高程序的健壮性</span><br /><span style="font-size: 12pt">const赋值</span><br /><span style="font-size: 12pt">[思考1]： 以下的这种赋值方法正确吗？const A* c=new A();A* e = c;</span><br /><span style="font-size: 12pt">这种方法不正确，因为声明指针的目的是为了对其指向的内容进行改变，而声明的指针e指向的是一个常量，所以不正确；</span><br /><span style="font-size: 12pt">[思考2]： 以下的这种赋值方法正确吗？A* const c = new A();A* b = c;</span><br /><span style="font-size: 12pt">这种方法正确，因为声明指针所指向的内容可变；</span><br /><span style="font-size: 12pt">[思考3]： 这样定义赋值操作符重载函数可以吗？const A&amp; operator=(const A&amp; a);</span><br /><span style="font-size: 12pt">这种做法不正确；在const A::operator=(const A&amp; a)中，参数列表中的const的用法正确，而当这样连续赋值的时侯，问题就出现了：A a,b,c:(a=b)=c;因为a.operator=(b)的返回值是对a的const引用，不能再将c赋值给const常量。</span><br /><span style="font-size: 12pt">使用const的一些建议</span><br /><span style="font-size: 12pt">1 要大胆的使用const，这将给你带来无尽的益处，但前提是你必须搞清楚原委；</span><br /><span style="font-size: 12pt">2 要避免最一般的赋值操作错误，如将const变量赋值，具体可见思考题；</span><br /><span style="font-size: 12pt">3 在参数中使用const应该使用引用或指针，而不是一般的对象实例，原因同上；</span><br /><span style="font-size: 12pt">4 const在成员函数中的三种用法（参数、返回值、函数）要很好的使用；</span><br /><span style="font-size: 12pt">5 不要轻易的将函数的返回值类型定为const;6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;</span></p>
<p><br /><span style="font-size: 12pt">参考自：</span><a href="http://www.cppblog.com/mzty/archive/2005/11/09/1001.html"><span style="font-size: 12pt">http://www.cppblog.com/mzty/archive/2005/11/09/1001.html</span></a><br /></p> <img src ="http://www.cppblog.com/TinYShoW/aggbug/195275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/TinYShoW/" target="_blank">HiHi..!</a> 2012-11-16 16:28 <a href="http://www.cppblog.com/TinYShoW/articles/195275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>volatile关键字</title><link>http://www.cppblog.com/TinYShoW/articles/195272.html</link><dc:creator>HiHi..!</dc:creator><author>HiHi..!</author><pubDate>Fri, 16 Nov 2012 07:33:00 GMT</pubDate><guid>http://www.cppblog.com/TinYShoW/articles/195272.html</guid><wfw:comment>http://www.cppblog.com/TinYShoW/comments/195272.html</wfw:comment><comments>http://www.cppblog.com/TinYShoW/articles/195272.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/TinYShoW/comments/commentRss/195272.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/TinYShoW/services/trackbacks/195272.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt">volatile关键字是一种类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素更改，比如：操作系统、硬件或者其它线程等。遇到这个关键字声明的变量，编译器对访问该变量的代码就</span><span style="color: red; font-size: 12pt">不再进行优化</span><span style="font-size: 12pt">，从而可以提供对特殊地址的稳定访问。</span><br /><br /><span style="font-size: 12pt">使用该关键字的例子如下：</span><br /><span style="font-size: 12pt">int volatile nVint;</span><br /><span style="font-size: 12pt">当要求使用volatile 声明的变量的值的时候，系统总是</span><span style="color: red; font-size: 12pt">重新</span><span style="color: red; font-size: 12pt">从它所在的内存读取数据</span><span style="font-size: 12pt">，即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。</span><br /><br /><span style="font-size: 12pt">例如：</span><br /><span style="font-size: 12pt">volatile int i=10;</span><br /><span style="font-size: 12pt">int a = i;</span><br /><span style="font-size: 12pt">...</span><br /><span style="font-size: 12pt">//其他代码，并未明确告诉编译器，对i进行过操作</span><br /><span style="font-size: 12pt">int b = i;&nbsp;</span><br /><span style="font-size: 12pt">volatile 指出 i是随时可能发生变化的，每次使用它的时候必须从i的地址中读取，因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是，由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作，它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来，如果i是一个寄存器变量或者表示一个端口数据就容易出错，所以说</span><span style="color: red; font-size: 12pt">volatile可以保证对特殊地址的稳定访问。</span><br /><span style="font-size: 12pt">注意，在vc6中，一般调试模式没有进行代码优化，所以这个关键字的作用看不出来。下面通过插入汇编代码，测试有无volatile关键字，对程序最终代码的影响：</span><br /><span style="font-size: 12pt">首先，用classwizard建一个win32 console工程，插入一个voltest.cpp文件，输入下面的代码：</span><br /><span style="font-size: 12pt">#include &lt;stdio.h&gt;</span><br /><span style="font-size: 12pt">void main()</span><br /><span style="font-size: 12pt">{</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">int i=10;</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">int a = i;</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">printf("i= %d\n",a);</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">//下面汇编语句的作用就是改变内存中i的值，但是又不让编译器知道</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">__asm {</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">mov dword ptr [ebp-4], 20h</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">}</span><br /><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">int b = i;</span><br />&nbsp;&nbsp;&nbsp;<span style="font-size: 12pt">printf("i= %d\n",b);</span><br /><span style="font-size: 12pt">}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>
<p><span style="font-size: 12pt">然后，在调试版本模式运行程序，输出结果如下：</span></p><pre><span style="font-size: 12pt">i = 10
i = 32</span></pre>
<p><span style="font-size: 12pt">然后，在release版本模式运行程序，输出结果如下：</span></p><pre><span style="font-size: 12pt">i = 10
i = 10</span></pre>
<p><span style="font-size: 12pt">输出的结果明显表明，release模式下，编译器对代码进行了优化，第二次没有输出正确的i值。下面，我们把 i的声明加上volatile关键字，看看有什么变化：</span><br /><span style="font-size: 12pt">#include &lt;stdio.h&gt;</span><br /><span style="font-size: 12pt">void main()</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;volatile int i=10;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;int a = i;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;printf("i= %d\n",a);</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;__asm {</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov dword ptr [ebp-4], 20h</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;}&nbsp;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;int b = i;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;printf("i= %d\n",b);</span><br /><span style="font-size: 12pt">}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span style="font-size: 12pt">分别在debug版本和release版本运行程序，输出都是：</span></p><pre><span style="font-size: 12pt">i = 10
i = 32</span></pre>
<p><span style="font-size: 12pt">这说明这个关键字发挥了它的作用！<br /><br />参考自：<a href="http://www.cppblog.com/mzty/archive/2006/08/08/10959.html">http://www.cppblog.com/mzty/archive/2006/08/08/10959.html</a></span></p><img src ="http://www.cppblog.com/TinYShoW/aggbug/195272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/TinYShoW/" target="_blank">HiHi..!</a> 2012-11-16 15:33 <a href="http://www.cppblog.com/TinYShoW/articles/195272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>extern</title><link>http://www.cppblog.com/TinYShoW/articles/195271.html</link><dc:creator>HiHi..!</dc:creator><author>HiHi..!</author><pubDate>Fri, 16 Nov 2012 07:23:00 GMT</pubDate><guid>http://www.cppblog.com/TinYShoW/articles/195271.html</guid><wfw:comment>http://www.cppblog.com/TinYShoW/comments/195271.html</wfw:comment><comments>http://www.cppblog.com/TinYShoW/articles/195271.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/TinYShoW/comments/commentRss/195271.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/TinYShoW/services/trackbacks/195271.html</trackback:ping><description><![CDATA[<div class="postText"><span style="font-size: 12pt">1、extern可以置于变量声明前； </span><br /><span style="font-size: 12pt">2、extern也可以置于函数声明前； 通过这种行为它告诉编译器：该变量/函数的定义已经存在在某个地方了，让编译器到其他的模块去寻找它的定义。 </span><br /><span style="font-size: 12pt">3、extern &#8220;C&#8221; 使用extern&#8220;C&#8221;主要是因为C++语言在编译的时候为了实现多态，会将函数名和函数结合起来形成另外一种函数名（总之就是说编译后的函数名与你之前自己声明时的函数名会不一样），而C语言中无多态的概念当然也就不会有这种奇异的名字变化问题。这是问题就出现了，当你要在C++中调用C函数时，由于名字的不同，所以它会找不到所调用的这个函数的定义，因而会出错。 为了解决这一C与C++的矛盾冲突，就有了extern &#8220;C&#8221;。</span><br /><br /><span style="font-size: 12pt">参考自：</span><a href="http://www.cppblog.com/mzty/archive/2006/07/14/9834.html"><span style="font-size: 12pt">http://www.cppblog.com/mzty/archive/2006/07/14/9834.html</span></a></div><img src ="http://www.cppblog.com/TinYShoW/aggbug/195271.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/TinYShoW/" target="_blank">HiHi..!</a> 2012-11-16 15:23 <a href="http://www.cppblog.com/TinYShoW/articles/195271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>using 实例</title><link>http://www.cppblog.com/TinYShoW/articles/195270.html</link><dc:creator>HiHi..!</dc:creator><author>HiHi..!</author><pubDate>Fri, 16 Nov 2012 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/TinYShoW/articles/195270.html</guid><wfw:comment>http://www.cppblog.com/TinYShoW/comments/195270.html</wfw:comment><comments>http://www.cppblog.com/TinYShoW/articles/195270.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/TinYShoW/comments/commentRss/195270.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/TinYShoW/services/trackbacks/195270.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt">class CBase</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;public print();</span><br /><span style="font-size: 12pt">};</span><br /><span style="font-size: 12pt">如果子类私有或保护继承自基类，那么此时子类的对象是不能调用基类公有的成员的。</span><br /><span style="font-size: 12pt">class CChild : private CBase</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">}</span><br /><span style="font-size: 12pt">void main()</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;CChild child;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;child.print();//此时的print()为私有的，child 就不能调用</span><br /><span style="font-size: 12pt">} </span><br /><span style="font-size: 12pt">=====================================================</span><br /><span style="font-size: 12pt">但是用using在子类中声明基类的公有成员后，此成员在子类中认为共有，可以访问。 </span><br /><span style="font-size: 12pt">class CChild : private CBase</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">public：</span><br /><span style="color: red; font-size: 12pt">&nbsp;&nbsp;&nbsp;using</span><span style="font-size: 12pt"> CBase::print(); </span><br /><span style="font-size: 12pt">}</span><br /><span style="font-size: 12pt">void main()</span><br /><span style="font-size: 12pt">{</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;CChild child;</span><br /><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;child.print();</span><br /><span style="font-size: 12pt">} </span><img src ="http://www.cppblog.com/TinYShoW/aggbug/195270.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/TinYShoW/" target="_blank">HiHi..!</a> 2012-11-16 15:20 <a href="http://www.cppblog.com/TinYShoW/articles/195270.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>虚函数理解</title><link>http://www.cppblog.com/TinYShoW/articles/164160.html</link><dc:creator>HiHi..!</dc:creator><author>HiHi..!</author><pubDate>Sat, 14 Jan 2012 04:34:00 GMT</pubDate><guid>http://www.cppblog.com/TinYShoW/articles/164160.html</guid><wfw:comment>http://www.cppblog.com/TinYShoW/comments/164160.html</wfw:comment><comments>http://www.cppblog.com/TinYShoW/articles/164160.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/TinYShoW/comments/commentRss/164160.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/TinYShoW/services/trackbacks/164160.html</trackback:ping><description><![CDATA[<p><span style="font-size: 13px"><span style="font-family: Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C++</span><span style="line-height: 24px; font-family: 宋体" lang="ZH-CN">中的虚函数的作用主要是实现了多态的机制。关于多态，简而言之就是用父类类型的指针指向其子类的实例，然后通过父类的指针调用实际子类的成员函数。然后在运行时决定选用父类函数还是子类函数。<br /><font size="2">&nbsp;&nbsp; 虚函数<span style="line-height: 24px; font-family: 宋体" lang="ZH-CN">是通过一张虚函数表</span><span style="line-height: 24px; font-family: 宋体" lang="ZH-CN">来实现的。<font size="2">虚函数表是一个类的虚函数的地址表，这张表<font size="2">解决了继承、覆盖的问题，反应了</font>类中虚函数的真实对应关系。<br />&nbsp;&nbsp;&nbsp;<font size="2"><span style="font-family: Times New Roman">C++</span><span style="line-height: 24px; font-family: 宋体" lang="ZH-CN">的编译器保证虚函数表的指针存在于对象实例中最前面的位置，这是为了保证取到虚函数表的有最高的性能。<span style="line-height: 24px; font-family: 宋体" lang="ZH-CN"><font size="2">这意味着我们通过对象实例的地址得到虚函数表，然后就可以遍历其中函数指针，并调用相应的函数。关于这些，下面有个清晰的说明。<br />&nbsp;&nbsp;&nbsp;定义Base和Derive：<br /></font></font></font></font></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Base<br />{<br /></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;func1()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">"</span><span style="color: #000000">base1()</span><span style="color: #000000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;func2()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">"</span><span style="color: #000000">base2()</span><span style="color: #000000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />};</span></div>
<p>&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Derive&nbsp;:&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Base<br />{<br /></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;func1()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">"</span><span style="color: #000000">derive1()</span><span style="color: #000000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">endl;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />};</span></div>
<p>&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">定义函数指针Fun</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">(</span><span style="color: #000000">*</span><span style="color: #000000">Function)(</span><span style="color: #0000ff">void</span><span style="color: #000000">);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">定义Base对象</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Base&nbsp;</span><span style="color: #0000ff">base</span><span style="color: #000000">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;Function&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;NULL;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">验证虚函数表的指针存在于对象实例中最前面的位置</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">*</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">*</span><span style="color: #000000">)(</span><span style="color: #000000">&amp;</span><span style="color: #0000ff">base</span><span style="color: #000000">));<br />&nbsp;&nbsp;&nbsp;&nbsp;pFunction();</span><span style="color: #008000">//</span><span style="color: #008000">输出base1(),即pFunction为func1(),说明了虚函数表的指针存在于对象实例中最前面的位置.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">同理</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">*</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)(</span><span style="color: #000000">&amp;</span><span style="color: #0000ff">base</span><span style="color: #000000">)</span><span style="color: #000000">+</span><span style="color: #000000">1</span><span style="color: #000000">);<br />&nbsp;&nbsp;&nbsp;&nbsp;pFunction();</span><span style="color: #008000">//</span><span style="color: #008000">输出base2();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">同样的方法访问derive中的函数&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Derive&nbsp;derive;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">**</span><span style="color: #000000">&nbsp;pVtab&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">**</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">derive;<br />&nbsp;&nbsp;&nbsp;&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)pVtab[</span><span style="color: #000000">0</span><span style="color: #000000">][</span><span style="color: #000000">0</span><span style="color: #000000">];<br />&nbsp;&nbsp;&nbsp;&nbsp;pFunction();</span><span style="color: #008000">//</span><span style="color: #008000">由于被子类func1覆盖，输出derive1();</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)pVtab[</span><span style="color: #000000">0</span><span style="color: #000000">][</span><span style="color: #000000">1</span><span style="color: #000000">];<br />&nbsp;&nbsp;&nbsp;&nbsp;pFunction();</span><span style="color: #008000">//</span><span style="color: #008000">输出base2();</span><span style="color: #008000"><br /></span><span style="color: #000000"><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>
<p>虚函数表：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/tinyshow/无标题.png" width="418" height="451" /><br />下面介绍下多重继承。<br /><strong>无覆盖：<br /></strong><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/tinyshow/fffff.jpg" width="284" height="193" /><br /><font size="2">子类实例中的虚函数表</font>：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/tinyshow/QQ截图20120114120850.png" width="496" height="174" /><br /><span style="line-height: 21px; font-family: 宋体" lang="ZH-CN"><span style="font-size: 13px">1)每个父类都有自己的虚表。</span></span> <br />2)<span style="line-height: 21px; font-family: 宋体" lang="ZH-CN"><span style="font-size: 13px">子类的成员函数被放到了第一个父类的表中。（所谓的第一个父类是按照声明顺序来判断的）</span></span></p>
<p><strong>有覆盖：<br /></strong><font size="2">在子类中覆盖了父类的<span style="font-family: Times New Roman">f()</span><span style="line-height: 24px; font-family: 宋体" lang="ZH-CN">函数</span></font><br /><font size="2">子类实例中的虚函数表</font>：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/tinyshow/o_vtable5.jpg" width="420" height="173" /><br /><br />一些特别的说明：<br /><strong><font size="2">通过父类型的指针访问子类自己的虚函数</font></strong><br />在正上方这个图中，我们无法这样访问g1：<br /><span style="line-height: 18px; font-family: Tahoma; font-size: 9pt">Base1 *b1 =&nbsp;<span style="line-height: 18px; color: blue">new</span>&nbsp;Derive();</span> </p>
<p style="padding-bottom: 0px; margin: 0in 0in 0pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 18px; font-family: Tahoma; font-size: 9pt">b1-&gt;g1();<span style="line-height: 18px">&nbsp;&nbsp;</span></span><span style="line-height: 18px; font-family: Fixedsys; color: green; font-size: 9pt">//<span style="line-height: 18px" lang="ZH-CN">编译出错<br /><br /></span><span style="line-height: 18px; color: #000000" lang="ZH-CN">但是我们可以采用下面的方法，通过<font size="2"><span style="color: #000000">指针的方式访问虚函数</span></font></span><span style="line-height: 18px; color: #000000" lang="ZH-CN">。</p></span><span style="line-height: 18px; font-family: Fixedsys; color: green; font-size: 9pt"><span style="line-height: 18px; color: #000000" lang="ZH-CN">
<p style="padding-bottom: 0px; margin: 0in 0in 0pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"></span><span style="line-height: 18px; color: #000000" lang="ZH-CN">&nbsp;</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">Base&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">b&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Derive();<br />pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">*</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)(b)&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">);<br />pFunction();</span><span style="color: #008000">//</span><span style="color: #008000">Derive:g1();</span></div>
<p style="padding-bottom: 0px; margin: 0in 0in 0pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"></span></span>&nbsp;</p></span>
<p>&nbsp;</p>
<p><strong><font size="2">通过子类类型的指针访问父类自己的私有虚函数</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Base&nbsp;{<br /></span><span style="color: #0000ff">private</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;f()&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Base::f</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;endl;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />};<br /><br /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Derive&nbsp;:&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Base<br />{<br />};<br /></span></div>
<p>调用</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">Derive&nbsp;d;<br />Function&nbsp;&nbsp;pFunction&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(Function)</span><span style="color: #000000">*</span><span style="color: #000000">((</span><span style="color: #0000ff">int</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">*</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">*</span><span style="color: #000000">)(</span><span style="color: #000000">&amp;</span><span style="color: #000000">d)</span><span style="color: #000000">+</span><span style="color: #000000">0</span><span style="color: #000000">);<br />pFunction();<br /><br /></span></div>
<p></font></strong><br />参考自<span style="font-size: 13px"><span style="line-height: 24px; font-family: 宋体" lang="ZH-CN"><a href="http://blog.csdn.net/liufei_learning/article/details/5443282" rel="nofollow">http://blog.csdn.net/liufei_learning/article/details/5443282</a></span></span></span></span></span></span></span>&nbsp;</p><img src ="http://www.cppblog.com/TinYShoW/aggbug/164160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/TinYShoW/" target="_blank">HiHi..!</a> 2012-01-14 12:34 <a href="http://www.cppblog.com/TinYShoW/articles/164160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>