??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品国产字幕久久不卡,99久久国产综合精品网成人影院 ,亚洲人成无码www久久久http://www.shnenglu.com/Cass/category/17825.htmlzh-cnThu, 01 Dec 2011 06:07:42 GMTThu, 01 Dec 2011 06:07:42 GMT60q度条控?/title><link>http://www.shnenglu.com/Cass/archive/2011/11/30/161250.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Wed, 30 Nov 2011 12:42:00 GMT</pubDate><guid>http://www.shnenglu.com/Cass/archive/2011/11/30/161250.html</guid><wfw:comment>http://www.shnenglu.com/Cass/comments/161250.html</wfw:comment><comments>http://www.shnenglu.com/Cass/archive/2011/11/30/161250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Cass/comments/commentRss/161250.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Cass/services/trackbacks/161250.html</trackback:ping><description><![CDATA[     摘要: Style Description <br>PBS_SMOOTH //qx <br>PBS_VERTICAL //垂直 <br> 响应消息 <br> <br>PBM_DELTAPOS //一个进度条׃个指定的增量当前位置和重l栏Q以反映新的位置?<br>wParam=Q的WPARAMQnIncrement <br>lParam = 0; <br>q回原来的位|?<br> <br>  <a href='http://www.shnenglu.com/Cass/archive/2011/11/30/161250.html'>阅读全文</a><img src ="http://www.shnenglu.com/Cass/aggbug/161250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:42 <a href="http://www.shnenglu.com/Cass/archive/2011/11/30/161250.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++d?/title><link>http://www.shnenglu.com/Cass/archive/2011/11/30/161249.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Wed, 30 Nov 2011 12:40:00 GMT</pubDate><guid>http://www.shnenglu.com/Cass/archive/2011/11/30/161249.html</guid><wfw:comment>http://www.shnenglu.com/Cass/comments/161249.html</wfw:comment><comments>http://www.shnenglu.com/Cass/archive/2011/11/30/161249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Cass/comments/commentRss/161249.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Cass/services/trackbacks/161249.html</trackback:ping><description><![CDATA[<p>  和C语言不同QC++Ҏ(gu)件的操作有自qҎ(gu)?br />        C++Ҏ(gu)件的操作主要是通过两个c(ofstream---向文件中写入数据。ifstream----从文件中d数据Q,通过指定cM的变量取值来辑ֈҎ(gu)件的操作?br />       ofstreamcȝ构造函敎ͼ有好几个Q这个用的最多)(j)ofstream::ofstream <br />ofstream( const char* szName, int nMode = ios::out, int nProt = filebuf::openprot )</p> <p>szName:指定要打开的文件名</p> <p>nMode:指定打开的方式,有以下几U取?</p> <p> </p> <p>--------------------------------------------------------------------------------</p> <p>ios::app   数据始终d在文件的末尾Q文件的指针不移动。比如输入的?23Q在文g的末և现的?21Q先?插入文g,接下来插?Q??的前?...Q?/p> <p><br />ios::ate   数据d在文件的末尾Q文件指针会(x)UdQ比如输?23Q在文g的末ְ出现123.</p> <p><br />ios::in   如果指定?jin)此模式Q则文g的内容不?x)被截?/p> <p><br />ios::out   打开文gQ用于输出,可以用于所有的ofstream对象</p> <p><br />ios::trunc   如果文g已经存在Q那么文件的内容被清空</p> <p><br />ios::nocreate   打开文g的时候不创徏文gQ意思是如果文g不存在,则函数失?/p> <p><br />ios::noreplace   不覆盖文Ӟ意思是如果文g存在Q则函数调用p|?/p> <p><br />ios::binary   以二q制方式打开文gQ默认是以文本方式打开</p> <p><br />--------------------------------------------------------------------------------<br />nProt:指定文g保护规格说明Q有以下几种取?br />filebuf::sh_compat   兼容׃n模式filebuf::openprot和此U方式一?br />filebuf::sh_none   独占模式Q不׃n<br />filebuf::sh_read    ׃nQ只L?br />filebuf::sh_write   ׃nQ可以对文g执行写入操作</p> <p>从文件中d数据是通过ifstream的对象进行的Q其构造函数如?br />ifstream::ifstream <br />ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );各参数的意义同上</p> <p>对于C++的文件操作,需要先构徏ofstream和ifstreamcȝ对象Q然后通过该对象的成员函数q行文g的读写操作(例如write和read函数Q?/p> <p>例子Q?/p> <p>#include <br />#include <br />#include <br />using namespace std;</p> <p>int main()<br />{<br />    //打开文gQ如果文件不存在则创建文Ӟ然后向文件内写入数据<br />    ofstream outFile("2.txt",ios::app);<br />    //数据写入文?br />    outFile.write("c++Ҏ(gu)件的操作Ҏ(gu)",strlen("c++Ҏ(gu)件的操作Ҏ(gu)"));<br />    outFile.close();</p> <p>    //在文件的末尾写入数据Q先文件的指针Ud末尾<br />    outFile.open("2.txt",ios::app);<br />    outFile.seekp(0,ios::end);<br />    outFile.write(",重复写一ơ:(x)c++Ҏ(gu)件的操作Ҏ(gu)",strlen(",重复写一ơ:(x)c++Ҏ(gu)件的操作Ҏ(gu)"));<br />    outFile.close();</p> <p>    //d文g的内容,q将其显C在屏幕?br />    ifstream inFile;<br />    inFile.open("2.txt",ios::in);<br />    char buffer[100];<br />    inFile.read(buffer,99);<br />    buffer[99]='';<br />    for(int i=0;i<100;i++)<br />        cout<<buffer[i];<br />    inFile.close();</p> <p>    return 0;<br />}<br /></p><img src ="http://www.shnenglu.com/Cass/aggbug/161249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:40 <a href="http://www.shnenglu.com/Cass/archive/2011/11/30/161249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于cȝ作用?Q全局?、类域、作用域Q?/title><link>http://www.shnenglu.com/Cass/archive/2011/11/30/161247.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Wed, 30 Nov 2011 12:33:00 GMT</pubDate><guid>http://www.shnenglu.com/Cass/archive/2011/11/30/161247.html</guid><wfw:comment>http://www.shnenglu.com/Cass/comments/161247.html</wfw:comment><comments>http://www.shnenglu.com/Cass/archive/2011/11/30/161247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Cass/comments/commentRss/161247.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Cass/services/trackbacks/161247.html</trackback:ping><description><![CDATA[     摘要: Q?Q、成员函?<br>成员函数有一个非成员函数不具有的属性——它的类itsclass 指向成员函数的指针必M向其赋值的函数cd匚w不是两个而是三个斚w都要匚wQ?<br>1 参数的类型和个数2 q回cd3 它所属的cȝ?<br> <br>例如cscreenQshort Screen::*ps_Screen = &Screen::_height; <br> <br>数据成员指针在被用来讉K数据成员之前必须先被l定C个对象或指针?<br> <br>// 所有指向类成员的指针都可以? 赋?<br>int (Screen::*pmf1)() = 0; <br>int (Screen::*pmf2)() = &Screen::height;//或者可以这样写Qint Screen::*pmf2 = &Screen::height; <br>注意Q静(rn)态类成员指针是该cȝ全局对象和函敎ͼ引用的是普通指?<br> <br> <br>(2)作用?<br> <br> <br>1.全局域、类域、局部域的区?<br> <br>  <a href='http://www.shnenglu.com/Cass/archive/2011/11/30/161247.html'>阅读全文</a><img src ="http://www.shnenglu.com/Cass/aggbug/161247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:33 <a href="http://www.shnenglu.com/Cass/archive/2011/11/30/161247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++的一些基http://www.shnenglu.com/Cass/archive/2011/11/30/161246.htmlYu_Yu_Wed, 30 Nov 2011 12:32:00 GMThttp://www.shnenglu.com/Cass/archive/2011/11/30/161246.htmlhttp://www.shnenglu.com/Cass/comments/161246.htmlhttp://www.shnenglu.com/Cass/archive/2011/11/30/161246.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/161246.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/161246.html
1、强制类型{换:(x)Q类型不同,而且不属于基本数据类?int double...)Ӟl常需要强制类型{?
①、显C强制类型{?
TYPE b = (TYPE) aQ?

C++中强制类型{换函数有4个:(x)
const_cast(用于去除const属性)(j)Q?
static_cast(用于基本cd的强制{换)(j)Q?
dynamic_cast(用于多态类型之间的cd转换Q,

  阅读全文

Yu_ 2011-11-30 20:32 发表评论
]]>
C/C++内存中的数据寚w问题http://www.shnenglu.com/Cass/archive/2011/10/01/157281.htmlYu_Yu_Sat, 01 Oct 2011 02:13:00 GMThttp://www.shnenglu.com/Cass/archive/2011/10/01/157281.htmlhttp://www.shnenglu.com/Cass/comments/157281.htmlhttp://www.shnenglu.com/Cass/archive/2011/10/01/157281.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/157281.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/157281.html数据寚wQ是指数据所在的内存地址必须是该数据长度的整数倍。比如DWORD数据的内存其实地址能被4除尽QW(xu)ORD数据的内存地址能被2除尽。x86 CPU能直接访问对齐的数据Q当它试图访问一个未寚w的数据时Q会(x)在内部进行一pd的调_(d)q些调整对于E序来说是透明的,但是?x)降低运行速度Q所以编译器在编译程序时?x)尽量保持数据对齐?/p>

C/C++~译器在内存分配时也保持?jin)数据对齐,L(fng)下例Q?/p>

struct{

short a1;

short a2;

short a3;

}A;

struct{

long  a1;

short a2;

}B;

cout<<sizeof(A)<<","<<sizeof(B)<<endl;//其它代码略去

l构体A和B的大分别是多少呢?

默认情况下,Z(jin)方便对结构体元素的访问和理Q当l构体内的元素都于处理器长度的时候,便以l构体里面最长的数据为对齐单位,也就是说Q?strong>l构体的长度一定是最长数据长度的整数倍?/strong>

如果l构体内部存在长度大于处理器位数时就以处理器位数为对齐单位?/p>

l构体内cd相同的连l元素将存在q箋的空间内Q和数组一栗?/p>

上例?

A?个shortcd变量Q各自占2字节Qd?Q??的倍数Q所以sizeof(A)=6;

B有一个longcd变量Q占4字节Q一个shortcd的变量,?字节Qd6不是最大长?的倍数Q所以要补空字节以增?实现寚wQ所以sizeof(8)=8?/p>

 

在C++cȝ设计中遵循同L(fng)道理Q但需注意Q空c需要占1个字节,?rn)态变?static)׃在栈中分配,不在sizeof计算范围内?/p>

Yu_ 2011-10-01 10:13 发表评论
]]>
虚函数和多?(?http://www.shnenglu.com/Cass/archive/2011/09/30/157256.htmlYu_Yu_Fri, 30 Sep 2011 15:17:00 GMThttp://www.shnenglu.com/Cass/archive/2011/09/30/157256.htmlhttp://www.shnenglu.com/Cass/comments/157256.htmlhttp://www.shnenglu.com/Cass/archive/2011/09/30/157256.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/157256.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/157256.html

多态性,q个面向对象~程领域的核?j)概念,本n的内容博大精深,要以一文说清楚实在是不太可能。加之作者本Zq在不断学习(fn)中,水^有限。因此本文只能描一下多态的轮廓Q读者能够了(jin)解个大概。如果有描的不准的地方,Ƣ迎指出Q或与作者探讨(作者EmailQnicrosoft@sunistudio.comQ?span class="Apple-converted-space"> 
        
        首先Q什么是多态(PolymorphisnQ?按字面的意思就?#8220;多种形状”。我手头的书上没有找C个多态的理论性的概念的描q。暂且引用一下Charlie   Calverts的对多态的描述?#8212;—多态性是允许你将父对象设|成为和一个或更多的他的子对象相等的技术,赋g后,父对象就可以Ҏ(gu)当前赋值给它的子对象的Ҏ(gu)以不同的方式运作(摘自“Delphi4   ~程技术内q?#8221;Q。简单的_(d)是一句话Q允许将子类cd的指针赋值给父类cd的指针。多态性在Object   Pascal和C++中都是通过虚函敎ͼVirtual   FunctionQ实现的?span class="Apple-converted-space"> 

        
        好,接着?#8220;虚函?#8221;Q或者是“虚方?#8221;Q。虚函数是允许被其子类重新定义的成员函数。而子c重新定义父c虚函数的做法,UCؓ(f)“覆盖”QoverrideQ,或者称?#8220;重写”?span class="Apple-converted-space"> 


        q里有一个初学者经常؜淆的概念。覆盖(overrideQ和重蝲QoverloadQ。上面说?jin),覆盖是指子类重新定义父类的虚函数的做法。而重载,是指允许存在多个同名函数Q而这些函数的参数表不同(或许参数个数不同Q或许参数类型不同,或许两者都不同Q。其实,重蝲的概念ƈ不属?#8220;面向对象~程”Q重载的实现是:(x)~译器根据函C同的参数表,对同名函数的名称做修饎ͼ然后q些同名函数成?jin)不同的函数Q至对于编译器来说是这L(fng)Q。如Q有两个同名函数Qfunction   func(p:integer):integer;和function   func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这L(fng)Qint_func、str_func。对于这两个函数的调用,在编译器间就已经定?jin),是?rn)态的Q记住:(x)是静(rn)态)(j)。也是_(d)它们的地址在编译期q定了(jin)Q早l定Q,因此Q重载和多态无养I真正和多态相关的?#8220;覆盖”。当子类重新定义?jin)父cȝ虚函数后Q父cL针根据赋l它的不同的子类指针Q动态(CQ是动态!Q的调用属于子类的该函数Q这L(fng)函数调用在编译期间是无法定的(调用的子cȝ虚函数的地址无法l出Q。因此,q样的函数地址是在q行期绑定的Q晚邦定Q。结论就是:(x)重蝲只是一U语aҎ(gu),与多态无养I与面向对象也无关Q?span class="Apple-converted-space"> 
        
        引用一句Bruce   Eckel的话Q?#8220;不要犯傻Q如果它不是晚邦定,它就不是多态?#8221; 
        
        那么Q多态的作用是什么呢Q我们知道,装可以隐藏实现l节Q得代码模块化Q承可以扩展已存在的代码模块(c)(j)Q它们的目的都是Z(jin)——代码重用。而多态则是ؓ(f)?jin)实现另一个目?#8212;—接口重用Q而且现实往往是,要有效重用代码很难,而真正最h价值的重用是接口重用,因ؓ(f)“接口是公司最有h(hun)值的资源。设计接口比用一堆类来实现这个接口更Ҏ(gu)间。而且接口需要耗费更昂늚人力的时间?#8221; 
        
        其实Q承的为重用代码而存在的理由已经来薄弱,因ؓ(f)“l合”可以很好的取代承的扩展现有代码的功能,而且“l合”的表现更好(臛_可以防止“cȝ?#8221;Q。因此笔者个为,l承的存在很大程度上是作?#8220;多?#8221;的基而非扩展现有代码的方式了(jin)?span class="Apple-converted-space"> 
        
        什么是接口重用Q我们D一个简单的例子Q假设我们有一个描q飞机的基类QObject   Pascal语言描述Q下同)(j)Q?span class="Apple-converted-space"> 
        type 
                plane   =   class 
                public 
                        procedure   fly();   virtual;   abstract;   //起飞U虚函数 
                        procedure   land();   virtual;   abstract;   //着陆纯虚函?span class="Apple-converted-space"> 
                        function   modal()   :   string;   virtual;   abstract;   //查寻型号U虚函数 
                end; 
        
        然后Q我们从planezZ个子c,直升机(copterQ和h式飞机(jetQ:(x) 
                copter   =   class(plane) 
                private 
                        fModal   :   String; 
                public 
                        constructor   Create(); 
                        destructor   Destroy();   override; 
                        procedure   fly();   override; 
                        procedure   land();   override; 
                        function   modal()   :   string;   override; 
                end; 
        
                jet   =   class(plane) 
                private 
                        fModal   :   String; 
                public 
                        constructor   Create(); 
                        destructor   Destroy();   override; 
                        procedure   fly();   override; 
                        procedure   land();   override; 
                        function   modal()   :   string;   override; 
                end; 
        
        现在Q我们要完成一个飞机控制系l,有一个全局的函?  plane_flyQ它负责让传递给它的飞机起飞Q那么,只需要这P(x) 
        procedure   plane_fly(const   pplane   :   plane); 
        begin 
                pplane.fly(); 
        end; 
        可以让所有传l它的飞机(plane的子cd象)(j)正常起飞Q不是直升是喷气机Q甚x现在q不存在的,以后?x)增加的飞碟。因为,每个子类都已l定义了(jin)自己的v飞方式?span class="Apple-converted-space"> 
        
        可以看到   plane_fly函数接受参数的是   planecd象引用,而实际传递给它的都是   plane的子cd象,现在回想一下开头所描述?#8220;多?#8221;Q多态性是允许你将父对象设|成为和一个或更多的他的子对象相等的技术,赋g后,父对象就可以Ҏ(gu)当前赋值给它的子对象的Ҏ(gu)以不同的方式运作?span class="Apple-converted-space"> 
        
        很显?dng)parent   =   child;   是多态的实质Q因为直升机“是一U?#8221;飞机Q喷气机?#8220;是一U?#8221;飞机Q因此,所有对飞机的操作,都可以对它们操作Q此Ӟ飞机cd作ؓ(f)一U接口?span class="Apple-converted-space"> 
        
        多态的本质是子cȝ型的指针赋值给父类cd的指针(在OP中是引用Q,只要q样的赋值发生了(jin)Q多态也׃生了(jin)Q因为实行了(jin)“向上映射”?/span>






多态?/span>

  是允?strong>父对象讄成ؓ(f)?/strong>一个或多个它的子对象相{?/strong>的技术,比如Parent:=ChildQ?多态性得能?strong>利用同一c?/strong>(基类)cd的指?/strong>?strong>引用不同cȝ对象,以及(qing)Ҏ(gu)所引用对象的不?/strong>,以不同的方式执行相同的操?

c++中多态更Ҏ(gu)理解的概念ؓ(f)

  允许父类指针或名U?/strong>?strong>引用子类对象Q或对象Ҏ(gu)Q而实际调用的Ҏ(gu)为对象的cȝ型方法?br />作用  
把不同的子类对象都当作父cL看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编E,以适应需求的不断变化?
  赋g后,父对象就可以Ҏ(gu)当前赋值给它的子对象的Ҏ(gu)以不同的方式运作。也是_(d)父亲的行为像儿子Q而不是儿子的行ؓ(f)像父二Ӏ?
  举个例子Q从一个基cMzQ响应一个虚命o(h)Q生不同的l果?
  比如从某个基cȝ承出多个对象Q其基类有一个虚Ҏ(gu)TdoitQ然后其子类也有q个Ҏ(gu)Q但行ؓ(f)不同Q然后这些子对象中的M一个可以赋l其基类的对象,q样其基cȝ对象可以执行不同的操作?jin)。实际上你是在通过其基cL讉K其子对象的,你要做的是一个赋值操作?
  使用l承性的l果是可以创徏一个类的家族,在认识这个类的家族时Q就是把导出cȝ对象当作基类的对象,q种认识又叫作upcasting。这栯识的重要性在于:(x)我们可以只针对基cdZD늨序,但它可以适应于这个类的家族,因ؓ(f)~译?/font>?x)自动就扑և合适的对象来执行操作。这U现象又UCؓ(f)多态性。而实现多态性的手段又叫U动态绑?dynamic binding)?
  单的_(d)建立一个父cȝ对象Q它的内容可以是q个父类的,也可以是它的子类?当子cL有和父类同样?a target="_blank">函数Q当使用q个对象调用q个函数的时候,定义q个对象的类Q也是父类Q里的同名函数将被调用,当在父类里的q个函数前加virtual关键字,那么子类的同名函数将被调用?/strong>

Yu_ 2011-09-30 23:17 发表评论
]]>
虚函数和多?(一)http://www.shnenglu.com/Cass/archive/2011/09/30/157249.htmlYu_Yu_Fri, 30 Sep 2011 13:58:00 GMThttp://www.shnenglu.com/Cass/archive/2011/09/30/157249.htmlhttp://www.shnenglu.com/Cass/comments/157249.htmlhttp://www.shnenglu.com/Cass/archive/2011/09/30/157249.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/157249.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/157249.html1、什么是虚函敎ͼ
①、虚函数必须是基cȝ?font color="#136ec2">?rn)态成?/font>函数
②、其讉K权限可以是protected或public。不能是private Q因为子cȝ承时Q子cM能访问?br />③、在~译时是动态联~的Q:(x)~译E序在编译阶Dƈ不能切知道要调用的函敎ͼ只有?strong>E序执行?/strong>才能定要调用的函敎ͼ为此要确切知道该调用的函敎ͼ要求联编工作要在E序q行时进行,q种在程序运行时q行联编工作被称为动态联~?动态联~规定,只能通过指向基类的指针或基类对象的引用来调用虚函?/span>

2、定义Ş式?br />virtual 函数q回值类?虚函数名QŞ参表Q?
  { 函数?}

U虚函数Qvirtual 函数?0   

3、虚函数内部机制?br />①、每个实例对象里有自q指针?br />②、虚函数QVirtual FunctionQ是通过一张虚函数表(Virtual TableQ来实现的?br />③、我们通过对象实例的地址得到q张虚函数表Q然后就可以遍历其中函数指针Qƈ调用相应的函数?br />例子Q?/span>
 

假设我们有这L(fng)一个类Q?

class Base {

public:

virtual void f() { cout << "Base::f" << endl; }

virtual void g() { cout << "Base::g" << endl; }

virtual void h() { cout << "Base::h" << endl; }

};

按照上面的说法,我们可以通过Base的实例来得到虚函数表?下面是实际例E:(x)

typedef void(*Fun)(void);

Base b;

Fun pFun = NULL;

cout << "虚函数表地址Q? << (int*)(&b) << endl;

cout << "虚函数表 — W一个函数地址Q? << (int*)*(int*)(&b) << endl;

/*q里的一点争议的个h看法*/

原文认ؓ(f)(int*)(&b)是虚表的地址Q而很多网友都_(d)Q包括我也认为)(j)Q?span style="color: red">(int *)*(int*)(&b)才是虚表地址

?span style="color: red">(int*)*((int*)*(int*)(&b)); 才是虚表W一个虚函数的地址?/p>

其实看后面的调用pFun = (Fun)*((int*)*(int*)(&b)); 可以看出,*((int*)*(int*)(&b));转成函数指针lpFunQ然后正的调用C(jin)虚函数virtual void f()?/p>

// Invoke the first virtual function

pFun = (Fun)*((int*)*(int*)(&b));

pFun();

实际q行l果如下Q?Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)

虚函数表地址Q?012FED4

虚函数表 — W一个函数地址Q?044F148

Base::f

通过q个CZQ我们可以看刎ͼ我们可以通过?amp;b转成int *Q取得虚函数表的地址Q然后,再次取址可以得到第一个虚函数的地址?jin),也就是Base::f()Q这在上面的E序中得C(jin)验证Q把int* 强制转成?jin)函数指针?j)。通过q个CZQ我们就可以知道如果要调用Base::g()和Base::h()Q其代码如下Q?

(Fun)*((int*)*(int*)(&b)+0); // Base::f()

(Fun)*((int*)*(int*)(&b)+1); // Base::g()

(Fun)*((int*)*(int*)(&b)+2); // Base::h()

q个时候你应该懂了(jin)吧。什么?q是有点晕。也是,q样的代码看着太ؕ?jin)。没问题Q让我画个图解释一下。如下所C:(x)

 


注意Q在上面q个图中Q我在虚函数表的最后多加了(jin)一个结点,q是虚函数表的结束结点,像字符串的l束W?#8220;\0”一P其标志了(jin)虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在WinXP+VS2003下,q个值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,q个值是如果1Q表C有下一个虚函数表,如果值是0Q表C是最后一个虚函数表?

下面Q我分别说?#8220;无覆?#8221;?#8220;有覆?#8221;时的虚函数表的样子。没有覆盖父cȝ虚函数是毫无意义的。我之所以要讲述没有覆盖的情况,主要目的是ؓ(f)?jin)给一个对比。在比较之下Q我们可以更加清楚地知道其内部的具体实现?

一般承(无虚函数覆盖Q?/strong>
下面Q再让我们来看看l承时的虚函数表是什么样的。假设有如下所C的一个承关p:(x)

 


h意,在这个承关pMQ子cL有重载Q何父cȝ函数。那么,在派生类的实例中Q其虚函数表如下所C:(x)

对于实例QDerive d; 的虚函数表如下:(x)

 


我们可以看到下面几点Q?

1Q虚函数按照其声明顺序放于表中?

2Q父cȝ虚函数在子类的虚函数前面?

我相信聪明的你一定可以参考前面的那个E序Q来~写一D늨序来验证?

一般承(有虚函数覆盖Q?/strong>
覆盖父类的虚函数是很昄的事情,不然Q虚函数变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了(jin)父类的虚函数Q会(x)是一个什么样子?假设Q我们有下面q样的一个承关pR?

 


Z(jin)让大家看到被l承q后的效果,在这个类的设计中Q我只覆盖了(jin)父类的一个函敎ͼ(x)f()。那么,对于zcȝ实例Q其虚函数表?x)是下面的一个样子:(x) 


我们从表中可以看C面几点,

1Q覆盖的f()函数被放C(jin)虚表中原来父c虚函数的位|?

2Q没有被覆盖的函C旧?

q样Q我们就可以看到对于下面q样的程序,

Base *b = new Derive();

b->f();

由b所指的内存中的虚函数表的f()的位|已l被Derive::f()函数地址所取代Q于是在实际调用发生Ӟ是Derive::f()被调用了(jin)。这实C(jin)多?/span>?

多重l承Q无虚函数覆盖)(j)
下面Q再让我们来看看多重l承中的情况Q假设有下面q样一个类的承关pR注意:(x)子类q没有覆盖父cȝ函数?

 


对于子类实例中的虚函数表Q是下面q个样子Q?

 

我们可以看到Q?

1Q?每个父类都有自己的虚表?

2Q?子类的成员函数被攑ֈ?jin)第一个父cȝ表中。(所谓的W一个父cL按照声明序来判断的Q?

q样做就是ؓ(f)?jin)解决不同的父类cd的指针指向同一个子cd例,而能够调用到实际的函数?

多重l承Q有虚函数覆盖)(j)
下面我们再来看看Q如果发生虚函数覆盖的情c(din)?

下图中,我们在子cM覆盖?jin)父cȝf()函数Q?nbsp;



下面是对于子cd例中的虚函数表的图:(x) 

我们可以看见Q三个父c虚函数表中的f()的位|被替换成了(jin)子类的函数指针。这P我们可以Q一?rn)态类型的父类来指向子c,q调用子cȝf()?jin)。如Q?

Derive d;

Base1 *b1 = &d;

Base2 *b2 = &d;

Base3 *b3 = &d;

b1->f(); //Derive::f()

b2->f(); //Derive::f()

b3->f(); //Derive::f()

b1->g(); //Base1::g()

b2->g(); //Base2::g()

b3->g(); //Base3::g()

安全?br />每次写C(j)++的文章,d不了(jin)要批判一下C++。这文章也不例外。通过上面的讲qͼ怿我们对虚函数表有一个比较细致的?jin)解了(jin)。水可蝲舟,亦可覆舟。下面,让我们来看看我们可以用虚函数表来q点什么坏事吧?

一、通过父类型的指针讉K子类自己的虚函数

我们知道Q子cL有重载父cȝ虚函数是一件毫无意义的事情。因为多态也是要Z函数重蝲的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数Q但我们Ҏ(gu)不可能用下面的语句来调用子cȝ自有虚函敎ͼ(x)

Base1 *b1 = new Derive();

b1->f1(); //~译出错

M妄图使用父类指针惌用子cM的未覆盖父类的成员函数的行ؓ(f)都会(x)被编译器视ؓ(f)非法Q所以,q样的程序根本无法编译通过。但在运行时Q我们可以通过指针的方式访问虚函数表来辑ֈq反C++语义的行为。(关于q方面的试Q通过阅读后面附录的代码,怿你可以做到这一点)(j)

二、访问non-public的虚函数

另外Q如果父cȝ虚函数是private或是protected的,但这些非public的虚函数同样?x)存在于虚函数表中,所以,我们同样可以使用讉K虚函数表的方式来讉Kq些non-public的虚函数Q这是很Ҏ(gu)做到的?

如:(x)

class Base {

private:

virtual void f() { cout << "Base::f" << endl; }

};

class Derive : public Base{

};

typedef void(*Fun)(void);

void main() {

Derive d;

Fun pFun = (Fun)*((int*)*(int*)(&d)+0);

pFun();

}

l束?br />C++q门语言是一门Magic的语aQ对于程序员来说Q我们似乎永q摸不清楚这门语a背着我们在干?jin)什么。需要熟(zhn)这门语aQ我们就必需要了(jin)解C++里面的那些东西,需要去?jin)解C++中那些危险的东西。不?dng)q是一U搬L(fng)头砸自己脚的~程语言?/p>


本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/hairetz/archive/2009/04/29/4137000.aspx



Yu_ 2011-09-30 21:58 发表评论
]]>
cȝ承和子类?多承和虚拟l承http://www.shnenglu.com/Cass/archive/2011/09/30/157232.htmlYu_Yu_Fri, 30 Sep 2011 08:18:00 GMThttp://www.shnenglu.com/Cass/archive/2011/09/30/157232.htmlhttp://www.shnenglu.com/Cass/comments/157232.htmlhttp://www.shnenglu.com/Cass/archive/2011/09/30/157232.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/157232.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/157232.html
//转自|友博客?br />1?nbsp;zcd象与普通类对象的相同之处在于,可以直接讉K该类的所有对象(包括this指针指向的对象和其他对象Q的protected和private成员Q包括其基类成员Q。不同之处在于派生类对象只能讉K其对应基cd象的protected成员Q有隐式this指针传递)(j)Q而不能访问其基类的其他对象的protect成员Q而普通类对象则也可以直接讉K该类所有对象的成员?/div>
 
2?nbsp;在C++中,基类指针只能讉K在该基类中被声明Q或l承Q的数据成员和成员函敎ͼ包括虚拟成员函数Q,而与它可能指向的实际对象无关Q所以如果需要用基类指针来访问一个没有在该基cM声明但是又在其派生类中定义了(jin)的成员,则需要执行dynamic_cast来完成从基类指针到派生类指针的安全向下{换。把一个成员声明ؓ(f)虚拟的,只推延了(jin)“在程序执行期间根据指针指向的实际cȝ型,对于要调用实例的解析q程”
 
3?nbsp;关于基类Q派生类的相兌充:(x)
1?nbsp;z表中指定的类必须先被定义好,方可被指定ؓ(f)基类?/div>
2?nbsp;zcȝ前向声明不能包括其派生表Q而只需要类名即可?/div>
3?nbsp;~省的承是private?/div>
4?nbsp;l承而来的派生类的虚拟函C般加上virtual较好Q也可以省略。但基类中一定要声明为virtual?/div>
5?nbsp;对于基类的静(rn)态成员,所有派生类对象都引用基cd建的q个相同Q单一Q共享的?rn)态成员,而不是创zcȝ另一个独立的?rn)态成员?/div>
6?nbsp;友员关系不会(x)被承,zcL有成?#8220;向它的基cL权友谊的c?#8221;的友员?/div>
 
4?nbsp;l承机制下,zcd象的构造函敎ͼ析构函数Q调用顺序ؓ(f)Q?/div>
1?nbsp;基类Q子对象的)(j)构造函敎ͼ若有多个基类Q则以类z表中出现的顺序ؓ(f)序?/div>
2?nbsp;成员cd象的构造函敎ͼ若有多个成员cd象,则以它们在类定义中被声明的顺序ؓ(f)序?/div>
3、派生类自己的构造函数?/div>
4、派生类对象的析构函数的调用序与它的构造函数相反。承机制下Q析构函数的行ؓ(f)如下Q派生类的析构函数先被调用,再静(rn)态调用基cȝ析构函数Q从直接基类开始)(j)。注意一般基cȝ析构函数不应该是protectedQ因拟函数承接了(jin)“调用者所属类cd的访问?#8221;。作Z般规则,我们类层次l构的根基类Q声明了(jin)一个或多个虚拟函数Q的析构函数声明拟的?/div>
 
5?nbsp;关于l承机制下基cL造函敎ͼ析构函数Q相关的几点说明Q?/div>
1?nbsp;作ؓ(f)一般规则,zcL造函数应不能直接向一个基cȝ数据成员赋|而是要把g递给适当的基cL造函数来辑ֈ初始化赋值的目的。(一般是通过成员初始化表的方式)(j)
2?nbsp;若基cM用于创徏对象Q则最好将其构造函数放在protect区,只允许其zcd象调用;若基cd允许创徏某一个特定的zcȝ型的对象Q则应该基cȝ构造函数放在private区,q将此特定的zcd明ؓ(f)该基cȝ友元来达到目的?/div>
3?nbsp;zcdƈ不承基cȝ构造函敎ͼ每个zc都必须提供自己的构造函数集Q派生类的构造函数只能合法的调用其直接基cȝ构造函数。(注意q里虚拟l承提供?jin)一个特例:(x)虚拟基类的初始化变成?jin)最l派生类的责任)(j)?/div>
 
6?nbsp;关于虚拟函数的相?/div>
1?nbsp;必须使用指针或者引用来支持虚拟函数机制Q面向对象程序设计)(j)Q基cd象由于其?rn)态编译,故不?x)保留派生类的类型n份?/div>
2?nbsp;W一ơ引入虚拟函数的基类Ӟ必须在类体中虚拟函数声明ؓ(f)virtualQ但若在该基cd部定义该虚拟函数时不能指定virtual。该基类的派生类中该虚拟函数virtual可加可不加,但从多重l承考虑Q最好加上?/div>
3?nbsp;zcL写的基类虚拟函数Q其原型必须与基c虚拟函数完全匹配(包括const和返回|(j)Q但q回值有个特例:(x)zcd例的q回值可以是基类实例q回cd的公有派生类cd?/div>
4?nbsp;U虚拟函敎ͼ声明后紧?0Q函数定义可写可不写Q只是提供了(jin)一个可被其zcL写的接口Q其本n不能通过虚拟机制被调用,但可以静(rn)态调用(写了(jin)函数定义的虚基类的纯虚拟函数Q。一般来_(d)虚拟函数的静(rn)态调用的目的是ؓ(f)?jin)效率(避免动态绑定)(j)?/div>
5?nbsp;包含Q或l承Q了(jin)一个或多个U虚拟函数的c被~译器识别ؓ(f)抽象基类Q抽象基cM能用来创建独立的cd象,只能作ؓ(f)子对象出现在后箋的派生类中?/div>
6、通过基类指针来调用的虚拟函数的真正实例是在运行时ȝ定的。但传给虚拟函数的缺省实参是在编译时L据被调用函数的对象的cd军_的(也即是若通过基类指针或引用调用派生类实例的虚拟函敎ͼ则传递给它的~省实参是由基类指定的)(j)?/div>
 
7?nbsp;虚拟l承和多l承相关Q?/div>
1?nbsp;虚拟l承主要实ؓ(f)?jin)解决承?jin)多个基类实例Q但是只需要一份单独的׃n实例的情c(din)?/div>
2?nbsp;非虚拟派生中Q派生类只能昑ּ的初始化其直接基c(x生类只能调用其直接基cȝ构造函敎ͼ(j)Q而在虚拟z中,虚拟基类的初始化变成?jin)最l派生类的责任,q个最l派生类是由每个特定的类对象声明来决定的Q其非虚拟基cȝ初始化同非虚拟派生一P只能由其直接zcd成。(即中间派生类的对于虚拟基cL造函数的调用被抑Ӟ(j)?/div>
3?nbsp;虚拟l承下构造函数的调用序按直接基cȝ声明序Q对每个l承子树(wi)作深度优先遍历。第一步按此顺序调用所有虚拟基cȝ构造函敎ͼW二步按此顺序调用非虚拟基类的构造函数。析构函数的调用序与构造函数相反?/div>
4?nbsp;虚拟基类成员的可视性,对于虚拟基类成员的承比该成员后来重新定义的实例权|优先U)(j),故特化的zcd例名覆盖?jin)共享的虚拟基类的实例名。而在非虚拟派生下的解析引用过E,每个l承得到的实例都有相同的权|优先U)(j)?/div>
5?nbsp;l承下派生类的类域被嵌套在基cȝ域中Q若一个名字在zcd中没有被解析出来Q则~译器在外围基类域中查找该名字定义。在多承下Q名字解析查找过Eؓ(f)先是在本cȝ域中查找Q再对承子?wi)中的所有基cd时查找,每个l承得到的实例都有相同的权|优先U)(j)。若在两个或多个基类子树(wi)中都扑ֈ?jin)该名字Q则对其的用是二义的?/div>

Yu_ 2011-09-30 16:18 发表评论
]]>深拷贝、浅拯 与拷贝构造函数的关系http://www.shnenglu.com/Cass/archive/2011/09/27/156903.htmlYu_Yu_Mon, 26 Sep 2011 17:24:00 GMThttp://www.shnenglu.com/Cass/archive/2011/09/27/156903.htmlhttp://www.shnenglu.com/Cass/comments/156903.htmlhttp://www.shnenglu.com/Cass/archive/2011/09/27/156903.html#Feedback0http://www.shnenglu.com/Cass/comments/commentRss/156903.htmlhttp://www.shnenglu.com/Cass/services/trackbacks/156903.html我的理解是:(x)

1、深拯和浅拯之间的区别在于是否复制了(jin)子对象?br />2、如果一个类拥有资源(堆,或者是其它pȝ资源)Q,当这个类的对象发生复制过E的时候,资源重新分配Q这个过E就是深拯Q反之对象存在资源,但复制过Eƈ未复制资源的情况视ؓ(f)拷贝?br />

当用一个已初始化过?jin)的自定义类cd对象d始化另一个新构造的对象的时候,拯构造函数就?x)被自动调用。也是_(d)当类的对象需要拷贝时Q拷贝构造函数将?x)被调用。以下情况都?x)调用拷贝构造函敎ͼ(x)
①、一个对象以g递的方式传入函数体:(x)q个好理解,因ؓ(f)传递给函数体的参数不是  str 而是 _str  ,是str的复制品。所以必然会(x)调用拯构造函数?nbsp;
②、一个对象以g递的方式从函数返?Q相当于构造一个新的对象?br />③、一个对象需要通过另外一个对象进行初始化。:(x)同上?br />
正如(zhn)理解那?“拷贝:(x)只拷贝对象的基本属性,其他的引用不拯Q还是保留引?#8221;如果在类中没有显式地声明一个拷贝构造函敎ͼ那么Q编译器会(x)自动生成一个默认的拯构造函敎ͼ该构造函数完成对象之间的位拷贝。当对象没有指针Ӟ按照上面的规则,则一切正常,拷贝把数据复制q新对象。但当对象有指针Ӟ因ؓ(f)拷贝引用不拯Q所以新对象与旧对象他们指向的是同一个内存区Q这时当释放内存时就出现释放两次Q出错了(jin)?br />
q时需要深拯..................
所以通常我们需要自己写拯构造函敎ͼ以免出现错误?br />//////////////参考资料所得,正确与否Ƣ迎讨论?br />

 



Yu_ 2011-09-27 01:24 发表评论
]]>
þþþòҰ¸߳| ޾þһح| ݺɫþۺ| Ʒһþ| ˾þ| þþ| ˾þô߽ۺ5g| Ʒþ99| þþþþþۺϺݺۺ| þþƷĻþ| þþƷУСŮ| 99þ99þþƷƬ| ޹þþþƷ | Ʒþþþþ99| þþþø߳ۺӰԺ| þùƷһ| þùVһë| þþþþùƷ볬| þþþùƷŮӰԺ| һþƵ| þþþƷþþþɫӰ| 91þþƷ91þɫ| ޾Ʒþþþþο| þ| þ99ƷþþþþҰ | þþۺϾɫۺϾ| þòӰ| 99þѹۺϾƷ| þþƷһAV| ŷһþþþþþô| þþþù˾Ʒҹ| ޹Ʒþþþ | þۺձ츾| þ99Ʒþþþþ벥 | ĻþþƷ1| þþþþùƷ| þۺϾɫۺϾƷ| ѹ99þþ㽶| ĻۺϾþ2| 99þˬ޾ƷŮ| ɫۺϾþþþ|