??xml version="1.0" encoding="utf-8" standalone="yes"?>少妇被又大又粗又爽毛片久久黑人,精品熟女少妇av免费久久,99精品伊人久久久大香线蕉http://m.shnenglu.com/Cass/category/17825.htmlzh-cnThu, 01 Dec 2011 06:07:42 GMTThu, 01 Dec 2011 06:07:42 GMT60q度条控?/title><link>http://m.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://m.shnenglu.com/Cass/archive/2011/11/30/161250.html</guid><wfw:comment>http://m.shnenglu.com/Cass/comments/161250.html</wfw:comment><comments>http://m.shnenglu.com/Cass/archive/2011/11/30/161250.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/Cass/comments/commentRss/161250.html</wfw:commentRss><trackback:ping>http://m.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://m.shnenglu.com/Cass/archive/2011/11/30/161250.html'>阅读全文</a><img src ="http://m.shnenglu.com/Cass/aggbug/161250.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:42 <a href="http://m.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://m.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://m.shnenglu.com/Cass/archive/2011/11/30/161249.html</guid><wfw:comment>http://m.shnenglu.com/Cass/comments/161249.html</wfw:comment><comments>http://m.shnenglu.com/Cass/archive/2011/11/30/161249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/Cass/comments/commentRss/161249.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/Cass/services/trackbacks/161249.html</trackback:ping><description><![CDATA[<p>  和C语言不同QC++Ҏ件的操作有自qҎ?br />        C++Ҏ件的操作主要是通过两个c(ofstream---向文件中写入数据。ifstream----从文件中d数据Q,通过指定cM的变量取值来辑ֈҎ件的操作?br />       ofstreamcȝ构造函敎ͼ有好几个Q这个用的最多)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文件指针会UdQ比如输?23Q在文g的末ְ出现123.</p> <p><br />ios::in   如果指定了此模式Q则文g的内容不会被截断</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++Ҏ件的操作Ҏ",strlen("c++Ҏ件的操作Ҏ"));<br />    outFile.close();</p> <p>    //在文件的末尾写入数据Q先文件的指针Ud末尾<br />    outFile.open("2.txt",ios::app);<br />    outFile.seekp(0,ios::end);<br />    outFile.write(",重复写一ơ:c++Ҏ件的操作Ҏ",strlen(",重复写一ơ:c++Ҏ件的操作Ҏ"));<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://m.shnenglu.com/Cass/aggbug/161249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:40 <a href="http://m.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://m.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://m.shnenglu.com/Cass/archive/2011/11/30/161247.html</guid><wfw:comment>http://m.shnenglu.com/Cass/comments/161247.html</wfw:comment><comments>http://m.shnenglu.com/Cass/archive/2011/11/30/161247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/Cass/comments/commentRss/161247.html</wfw:commentRss><trackback:ping>http://m.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静态类成员指针是该cȝ全局对象和函敎ͼ引用的是普通指?<br> <br> <br>(2)作用?<br> <br> <br>1.全局域、类域、局部域的区?<br> <br>  <a href='http://m.shnenglu.com/Cass/archive/2011/11/30/161247.html'>阅读全文</a><img src ="http://m.shnenglu.com/Cass/aggbug/161247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/Cass/" target="_blank">Yu_</a> 2011-11-30 20:33 <a href="http://m.shnenglu.com/Cass/archive/2011/11/30/161247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++的一些基http://m.shnenglu.com/Cass/archive/2011/11/30/161246.htmlYu_Yu_Wed, 30 Nov 2011 12:32:00 GMThttp://m.shnenglu.com/Cass/archive/2011/11/30/161246.htmlhttp://m.shnenglu.com/Cass/comments/161246.htmlhttp://m.shnenglu.com/Cass/archive/2011/11/30/161246.html#Feedback0http://m.shnenglu.com/Cass/comments/commentRss/161246.htmlhttp://m.shnenglu.com/Cass/services/trackbacks/161246.html
1、强制类型{换:Q类型不同,而且不属于基本数据类?int double...)Ӟl常需要强制类型{?
①、显C强制类型{?
TYPE b = (TYPE) aQ?

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

  阅读全文

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

C/C++~译器在内存分配时也保持了数据对齐,L下例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方便对结构体元素的访问和理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道理Q但需注意Q空c需要占1个字节,静态变?static)׃在栈中分配,不在sizeof计算范围内?/p>

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

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

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


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






多态?/span>

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

c++中多态更Ҏ理解的概念ؓ

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

Yu_ 2011-09-30 23:17 发表评论
]]>
虚函数和多?(一)http://m.shnenglu.com/Cass/archive/2011/09/30/157249.htmlYu_Yu_Fri, 30 Sep 2011 13:58:00 GMThttp://m.shnenglu.com/Cass/archive/2011/09/30/157249.htmlhttp://m.shnenglu.com/Cass/comments/157249.htmlhttp://m.shnenglu.com/Cass/archive/2011/09/30/157249.html#Feedback0http://m.shnenglu.com/Cass/comments/commentRss/157249.htmlhttp://m.shnenglu.com/Cass/services/trackbacks/157249.html1、什么是虚函敎ͼ
①、虚函数必须是基cȝ?font color="#136ec2">静态成?/font>函数
②、其讉K权限可以是protected或public。不能是private Q因为子cȝ承时Q子cM能访问?br />③、在~译时是动态联~的Q:~译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一个类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:

typedef void(*Fun)(void);

Base b;

Fun pFun = NULL;

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

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

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

原文认ؓ(int*)(&b)是虚表的地址Q而很多网友都_Q包括我也认为)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虚函数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然后,再次取址可以得到第一个虚函数的地址了,也就是Base::f()Q这在上面的E序中得C验证Q把int* 强制转成了函数指针)。通过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个时候你应该懂了吧。什么?q是有点晕。也是,q样的代码看着太ؕ了。没问题Q让我画个图解释一下。如下所C:

 


注意Q在上面q个图中Q我在虚函数表的最后多加了一个结点,q是虚函数表的结束结点,像字符串的l束W?#8220;\0”一P其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在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ȝ虚函数是毫无意义的。我之所以要讲述没有覆盖的情况,主要目的是ؓ了给一个对比。在比较之下Q我们可以更加清楚地知道其内部的具体实现?

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

 


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

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

 


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

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

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

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

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

 


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


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

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

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

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

Base *b = new Derive();

b->f();

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

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

 


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

 

我们可以看到Q?

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

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

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

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

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



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

我们可以看见Q三个父c虚函数表中的f()的位|被替换成了子类的函数指针。这P我们可以Q一静态类型的父类来指向子c,q调用子cȝf()了。如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++的文章,d不了要批判一下C++。这文章也不例外。通过上面的讲qͼ怿我们对虚函数表有一个比较细致的了解了。水可蝲舟,亦可覆舟。下面,让我们来看看我们可以用虚函数表来q点什么坏事吧?

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

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

Base1 *b1 = new Derive();

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

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

二、访问non-public的虚函数

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

如:

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背着我们在干了什么。需要熟悉这门语aQ我们就必需要了解C++里面的那些东西,需要去了解C++中那些危险的东西。不Ӟq是一U搬L头砸自己脚的~程语言?/p>


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



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

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

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

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

 



Yu_ 2011-09-27 01:24 发表评论
]]>
˾þô߽av| 99þþƷҹһ| ޹Ʒþ| ٸþĻ | ŷƷһþ| þþþþŮ| þþþav| þ99Ʒþ99ý| þseƷһƷ| þþþþҹƷ| þùһ| Ʒһþ㽶߿ۿ| ŮþþŮ| 99þùۺϾƷˮ| ۺϾþþƷɫ| ձƷþþĻ| ݺݾþ| 㽶þӰԺ| Ʒþþþþþþ| XxŷʸƷþþþþ| av˾þۺɫ| þþþAVۺϲҰ| ƷƵþþþ| ƷþþþþҰ| ƷŮþþþþ2018| Ʒþþþ9999| 99þۺϺݺۺϾþ| ˾þۺ| þƬѹۿ| պvavaŷvaþ| ˾þþAV츾ɫ| ݹƷþþþ| þѹƵ| þþƷˬӰ | һɫþ88Ʒۺ| avԾþþþa| þþþҹҹҹƷ| þþþþþۺϺݺۺ| ֻоƷþ| þþþþһƷ| Ļ˾Ʒþò |