-
GDT、GDTR、LDT、LDTR的理解 - [Linux]
2007-12-10
GDT是全局描述附表,主要存放操作系统和各任务公用的描述符,如公用的数据和代码段描述符、各任务的TSS描述符和LDT描述符。(TSS是任务状态段,存放各个任务私有运行状态信息描述符)
LDT是局部描述符表,主要存放各个任务的私有描述符,如本任务的代码段描述符和数据段描述符等。
GDTR是一个长度为48bit的寄存器,内容为一个32位的基地址和一个16位的段限。其中32位的基址是指GDT在内存中的地址。
LDTR是局部描述符寄存器,由一个可见的16位寄存器(段选择子)和一个不可见的描述符寄存器组成(描述符寄存器实际上是一个不可见的高速缓冲区)。
这里加入我的理解:应为GDT中除了有段描述符之外还有LDT描述符,所以微处理器在GDT中寻址LDT时,也需要使用选择子,以保持与段描述符寻址的统一。
在这里还要引入一个段选择子的概念。段选择子是一个寄存器,高13位用来指示描述符在描述符表中的索引号,低两位是表示使用描述符的特权级别;另外一位(T1)是GDT和LDT的信号量,如果T1=0,则使用GDTR,如果T1=1,则使用LDTR。选择子将被装入段寄存器中。系统中的段寄存器共有六个:CS、SS、DS、ES、FS和GS。当选择子被装入段寄存器时,微处理器会自动将其对应的描述符装入描述符寄存器。
系统任务切换时,LDT切换,而GDT不切换(因为真个系统只有一个GDT),这时新任务的LDT描述符的选择子就被装入到LDTR中。任务切换过程中,各个相关寄存器的变化?
当任务切换时,如果使用的是LDT,首先变化的是LDTR。段选择子被装入LDTR,同时LDT描述符自动被装入描述符寄存器。系统利用LDTR中的段选择子来定位LDT描述符在GDT中的位置。这里我不明白的是LDTR中的LDT描述符和GDT中的描述符是什么关系?为什么要这样做呢?自动装入到LDTR中的描述符到底是什么?从哪来?请高手指点!为什么要有一个GDTR,并且GDTR的结构和LDTR不一样呢?
这主要是因为系统只有一个GDT,而GDT的描述符有不能存放在GDT中(LDT的描述符都存放在GDT中),所以就需要一个GDTR来指示GDT在内存中的位置。因为GDTR是直接指示内存地址,而LDTR主要指示LDT描述符在GDT中的位置和属性,所以GDTR和LDTR的结构也不同。 -
源代码http://xmurobin.blogbus.com/files/11748459240.rar
可执行文件http://xmurobin.blogbus.com/files/11748459170.rar
ALT+D 是快捷跳出窗口
基本功能实现
其中核心代码memory class是抄别人的,呵呵
-
《肖申克的救赎》影评 - [杂谈]
2007-02-23
今天看了《肖申克的救赎》,感觉一般,不如想像中好看,好像看懂了,又好像没看懂......
后来看到这篇影评,果然是一部好片,难怪获得7项提名.......精彩....
-----------------
Some birds aren't meant to be caged, that's all. Their feathers are just too bright.
有些鸟儿是永远关不住的,因为它们的每一片羽翼上都沾满了自由的光辉!
Hope is a good thing, maybe the best of things, and no good thing ever dies.
希望是美好的,也许是人间至善,而美好的事物永不消逝。
《肖申克的救赎》(Shawshank Redemption)是我所看过令人震撼的一部电影之一。故事与其说讲述的是主人公安迪成功越狱、重获自由,倒不如说是安迪从灵魂到肉体获得拯救的过程。在我看来,这部电影所表现的深刻、玄奥的宗教、社会、人生哲理是该片受到赞扬的最重要的原因。也就是说这部片子触及到了人类灵魂最深处的东西,它反思的是一个关于体制化与反体制化、希望与绝望、灵魂救赎的深刻的主题。
institutionalized(体制化)、hope(希望)、redemption(救赎)是《肖》片中三个最为关键的灵魂性词语,理解了这三个词语,我们才能够很好的解读该片所探讨的主题。
第一个词语institutionalized(体制化),影片是通过瑞德(Mogran Freeman饰演)之口说出对这个词语的看法的。他说:“first you hate them ,then you get used to,enough time passes...you get so you depend on them 。That is instititutionalized(起初,你讨厌它,然后你逐渐的习惯它,足够的时间后你开始依赖他。这就是体制化)”。理解片中所谓的体制化,我们回顾一下老布(那个监狱的图书管理员)的一生就明白了。老布在监狱中也就是在一种体制下,渡过了50年,几乎就是一生的时间。可以想象,曾经年轻的布,在刚刚进入这种体制时,他肯定曾经像一切刚刚进入Shawshank的所有NEW fish(菜鸟)一样,愤世嫉俗,并试图反抗,然后和大部分的囚徒一样,他们逐渐发现:反抗等于徒劳,于是从对体制的反抗逐渐变为慢慢的接受然后学会适应体制,最后发展到对体制的严重依赖。可怜的老布,他的灵魂和肉体都已经完全体制化了,在垂暮之年却被放逐出体制之外,可以想象的到,老布在一个几乎完全陌生的体制下是根本无法存活的,此时老布与体制脱离无异于一个胎儿被斩断脐带,因此老布最终选择了结束自己的生命。
第二个词语hope(希望)。对这个词语的阐释是通过安迪和瑞德在午餐中的争论展开的。心存信念和希望的安迪说:“forget that there are ...places...in the world that aren't made out of stone,
there is something ...inside...that they can't get to...that is hope (不要忘了这个世界上还有可以穿透一切高墙的东西,它就在我们的内心深处,他们无法达到,也触摸不到,那就是希望)”,然而睿智的瑞德马上反驳说:“let me tell you something my friend 。hope is a dangerous thing hope can drive a man insane it's got no use on the inside.you'd better get used to that idea (让我来告诉你什么是希望,我的朋友。希望一个危险的东西,它能够使人疯狂,我们心中的希望根本毫无用处。你最好习惯这个观念)”
安迪的救赎 ——个人和群体的灵魂拯救
理解了以上两个词语,体制化和反体制化、希望和绝望,我们的主人公安迪开始了影片的主题——灵魂的救赎(redemption)。在Shawshank这个世界中,我们可以把人们划分成两大群体:体制内群体和体制外群体。体制内包括像典狱长和狱警在内,他们是体制的缔造者、执行者和维护者,以典狱长和那个凶狠的狱警无疑是撒旦的化身、穷凶极恶的统治者。而Shawshank的囚徒无疑是属于体制外的人群,他们是体制的服从者、被同化者。体制外的囚徒可以分为四类,以安迪为代表的英雄(hero),以瑞德为代表的精英(elite),以老布等为代表的大众(the masses),和以被虐待致死的肥仔为代表的失败者(alsoran)。英雄在灵魂上是超越体制的,尽管他们的肉体不得不服从体制的约束,然而英雄却能够利用自己伟大的灵魂和伟大的行动不断改变体制、超越体制。精英属于对体制有深刻清醒认识、曾经试图反抗但是最终选择妥协的那一类人。精英和英雄的共同之处在于在灵魂深处,二者都有希望存在。精英和英雄的区别在于,英雄除了在精神上笃信希望外,而且在行动上试图改变体制,这种卓越智慧的努力,正是是英雄成为英雄的根本所在。精英虽然在灵魂中尚有对希望的信仰,然而在行动上他们已经完全放弃了反抗的可能,他们在灵魂上虽然没有被体制化,但在肉体上已经完全体制化了。其次,就是绝大多数的大众(就是你我这样的芸芸众生),他们也曾经试图反抗,但是在强大的体制化的力量之下,他们却不幸的从精神到肉体完全被体制化了。最后,就是那些被淘汰的失败者,他们成了体制的祭品,很快被淹没在体制化的漩涡之中。
当然,安迪通过自己的行动不仅改变了自己的命运,而且深深的影响了牢笼中的其他人:安迪在狱中扩建图书馆,帮助其他犯人读书识字,那个拿到同等学历的问题青年就是被拯救的典型,一个跨掉一代中的嬉皮士竟然能够被教化成一个绅士,我们不得不感叹于救赎的力量。因此安迪的拯救不单单是一个个体的行为,还是一个群体的行为,这完全符合基督教关救赎的定义。影片在阐释安迪反抗的过程时,用了一个宗教性很强的词语——redemption(救赎)。追述这个词语的宗教渊源,我们很容易想起耶稣灵魂拯救的故事,事实上,在片中不知一次的出现过《圣经》,以及对《圣经》的引用。具有讽刺意味的是,那个道貌岸然的典狱长,外表似乎是一个圣洁的圣徒而他的行为和内心却肮脏的像魔鬼。在他的办公室旁边又一个精致的隽语:主的审判将要降临,然而这末日的审判却最终降临到这个审判者身上。
因此,《肖》片最重要的贡献在于对历史观的一种寓言式的阐述和对个体救赎、群体救赎的宗教式的反思。
对该片的反思——救赎就在你我心中
不难理解,Shawshank不过是一个寓言而已,它事实上就存在于我们现实的生活中。现实中的每一个人,都在自觉不自觉的扮演着Shawshank中囚徒或者狱方的角色。我们中的大部分人,都将沦为老布那样的命运,逐渐地被体制化直到严重地依赖体制,终其一生不曾越规逾矩。任何一种组织、制度、社会都可以视Shawshank为缩影。比如,我们的大学,某种程度上就是一个Shawshank城堡,当我们离开这座城堡时,我们中的绝大多数是注定要被体制化的,即使进入社会,体制对人的侵蚀也一刻没有停止过,社会历史就是在体制化和反抗体制化的循环中不断前进的,然而救赎却完全在于我们自己的选择,正如安迪的选择一样,再强大的体制也永远无法剥夺我们选择救赎的权利,因为,救赎就存在于我们的心中,那是任何强权也无法到达的地方。to being,or not to being,选择救赎还是选择绝望,选择英雄还是选择大众,选择上帝还是选择撒旦,这一切都在你我心中。 -
昨天终于把简化版的俄罗斯方块完工了,也多少完成了我的一个小心愿…….:)算法和过程模式依然是参考教程,放假还是太懒,不想动脑筋,仅仅改了一些自己看的不爽的地方!
总而言之,大概算法是加一个russia类,成员变量有当前下降方块图形Now[4][4],变形方块After[4][4],预告方块Will[4][4],还有m_nSpeed,m_nScore,m_nRowCount,m_nColCount
代表方块的图片m_btFuanKuai,背景m_btBK,在 view中定义m_russia[100][100]数组,然后通过Now[][]和m_russia[][]中元素的关系,算出应该在什么位置贴m_btFuanKuai的位图,再通过OnTimer,算出下一s的位置,赋值给m_russia[][],更新画图即可。总的来说,这个范例用的新的MFC 的东东不是很多,而且作者用了很多很土的方法,相信该作者那时候的C++水平不高。
产生一个0-Count中的数字
Srand(GetTickCount());
Int nTemp=rand()%Count;
关于键盘操作涉及到的函数是OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlag)
其中nChar为字母,View类中得到当前DC的方法,调用GetDC()就好了
关于Menu的对勾是相关于通告消息,OnUpdateMenuPause(CCmdUI* pCmdUI)
pCmdUI->SetCheck(m_bPause), 这样就关联了m_bPause
基本函数调用过程大概是
1 CView::OnDraw()中!start则调用Logo位图,不然就调用russia.DrawBK(pDC)
2 CRussia::DrawBK(pDC)中,加载BK位图,调用DrawScore(pDC)画分数之类的,根据int Russia[][]中的数值0/1来判断是否要加载m_btFuanKuai位图,根据Will[][]的0/1来画Will的方块图
3 CRussia::DrawScore(pDC) 中写字体,其中pDC->SetTextColor(RGB….), pDC->SetBkColor(pDC),注意要归还原先DC,int nOldDC=pDC->SaveDC();最后pDC->Restore(nOldDC
4 创建菜单的命令消息 调用russia.Start(),SetTimer(…..)
5 CRussia::Start()中,初始化参数, 清空背景Russia[][]=0,Will[][]=0,Now[][],然后调用DrawWill()画Will[][],再画Now[][]和Will[][]
6 CRussia::DrawWill(),将Now[][]=Will[][],并通过随机函数来产生一个Will[][],再将Will[][]平移到坐上角坐标
7 CView::OnTimer(UINT nIDEvent)来调用russia.move(MOVEDOWN),调用russia.DrawBK(GetDC) 进行重画
8 CView::OnKeyDown来判断按下的,调用不同的russia.move(….),再进行russia.DrawBK(…)重画,最后要释放定义的ReleaseDC(pDC)
9 CRussia::Move(int direction) 根据direction,先用Meet(Now,direction,NowPosition)判断时候可以移动,可以移动就改变NowPosition坐标,不能移动就保持不便。其中case MOVEDOWN时候,不能移动时候有可能会消行,调用LineDelete()来判断,加分!
10 CRussia::LineDelete() 就是检验数组Russia[][]是否有一行全为1,然后将那行去掉,上行移动到下行,并且统计消行的数目,改变m_nScore,函数结尾可以顺便判断游戏结束的条件。要注意该函数放的位置。是放在Now和russia累加前,还是累加后!
11 CRussia::Meet就是根据Now,russia当前数值,NowPosition数值,0,m_nColCount, m_nRowCount来判断是否可以移动。
12 CRussia::Change()在Move中MOVEUP:时候判断可以变形时候调用。就是旋转90度,然后平移到左上角。
13 菜单通告消息Pause,m_bPause=!m_bPause;进行killTimer(1)或SetTimer(….)
pCmdUI->SetCheck(m_bPause)
-
祝大家新年快乐,考研的考上研究生,找工作的找到好的工作!!呵呵!!!!
也祝福自己:
一切 顺利!
-
孔子说:学而不思则惘,思而不学则怠。学习和思考都很重要,学习之后的总结归纳很重要,象以前那样不系统,靠突击的方法的确不可取,日子久了很多问题就暴露出来的,知其然不知其所以然,无法提升到一个更高的境界。或者是拆东墙补西墙,这边捡起来,那边又忘记了。持之以恒的系统学习,再与一定实践相结合是关键~~
花了很空余的时间作了扫雷,核心算法都是看了资料的,不具备原创型,是抱着学习MFC,复习C++的目的。
定义一个雷的类,两个成员变量,一个是位图代号,也代表玩家的操作情况,二是雷的真实情况,周围有几个雷,本身自己是雷表示-1。
CMainFrame::OnCreate中是主窗体框架和状态栏,图标栏相关联,由于本例子中不需要这两个,可以在OnCreate 中把它们去掉!
CMainFrame::PreCreateWindow:该函数是在window创建前被调用,我们可以通过cs.style和 cs.dwExStyle,cs.cx,cs.cy来改变窗体的外观(置顶,样式,大小)。
CView:CView写整个程序的初始化,通过时间函数和随机函数,将数组bomb[row][col].m_nbombnumber赋值。CTime time = GetCurrentTime(); int s=time.GetSecond() 再利用rand()*s%m_RowCount得到在0-m_RowCount中的一个随机数。
CView::OnDraw界面的函数都写在这里
用画刷填充一定区域有3个步骤:1创建具体画刷CBrush mybrush; mybrush.CreateSolidBrush(RGB(0,0,0)); 2 定义填充区域CRect rect(a,b,c.d) 3 用画刷填充巨型区域pDC->FillRect(rect,&mybrush)
用画笔3个步骤 1创建具体画笔 CPen mypen; myPen.CreatePen(PS_SOLID,2,RGB(a,b,c));2将新画笔选到pDC中,并且保存旧画笔 CPen *myOldPen = pDC->SelectObject(&myPen); 3 用MoveTo,LineTo画线等等,最后还原旧画笔
用定义好的位图填充2个步骤 1 定义一个CDC, CDC Dc;用位图填充比较高级,哟啊用高级的东西:) 2 选定到Dc中Dc->SelectObject(m_BitMap),注意不是全局的pDC 3 用Dc填充pDc, pDC->BitBlt(x,y,x1,x2,&DC,0,0,SRCCOPY)
用字符字母填充1 保存旧的DC;int nOldDC=pDC->SaveDC(); 2 设置pDC的背景和样式 pDC->SetTextColor(RBG(…))和pDC->SetBkColor(RBG(…)) 3设置字体 CFont font; font.CreatePointFont(160,”…”);4选定到pDc中pDC->SelectObject(&font) 5 定义要显示的内容,多用到CString str;str.Format(“”,m_stt);pDC->TextOut(x,y,str);6释放pDC pDC->RestoreDC(nOldDC)
关于这些画图的,就是位图填充比较特殊,要自己再定义一个CDC,选到DC中的也不是全局的pDC,而是自己定义的Dc!另外,即使不传递pDC进来,通过GetDC()也能得到这个指针
CView::OnLButtonDown 这个函数用来改变OnDraw显示位图标识的成员变量,然后在OnDraw中根据不同的位图成员变量,画出不同的图.其中还用到Invalidate(),全部重画,这个函数要慎用,图象一直闪的问题都由可能是他说导致。解决方法是用部分重画的InvalidateRect(&rect),其中rect为定义好的重画区域。
所谓的按钮,都是一个一个的位图,通过定义鼠标按下的位置,来改变当前位置上显示的位图来起到按钮的效果
CView::OnCreate 这个函数伴随View类产生,本例将SetTimer(1,1000,NULL)放在这里。同时将KillTimer(1)放在结束时候,其中这个1都为Timer的标识。最后在OnTimer()的函数体内将有关记时器的变量改写.
程序基本完工
-
MFC诞生,运行,死亡的来龙去脉 CALLBACK函数 - [VC]
2007-02-16
MFC不二法门 :熟记MFC类的层次结构
1. MFC需要的函数库 有windows C Runtime;DLL Import;MFC函数库(AFX函数库),可在link.exe中设定相关选项
2. 需要的头文件:SDK只要载入windows.h,MFC则要其它一些,其中重要说两个:STDAFX.H(Precompiled header file)该文件中包含其它mfc头文件;AFXWIN.H,每个MFC都必须载如它,因为它以及它所载入的文件声明了所有的MFC 类.其中也有windows.h
关于Precompiled header file(预编译头文件)的说明:编译windows.h要消耗很多时间,为了节约编译过程中的时间而产生。Precompiled header就是将.H文件第一次编译后的结果存储起来,第二次编译可以直接从磁盘中取出。
3.MFC的来龙去脉
Mfc找不到WinMain函数,但是有个全局的theApp,其在WinMain前被初始化.
CWinApp 代表程序主体
CFrameWnd代表一个主框窗口
CWinApp—取代WinMain的地位,传统上SDK程序的WinMain所完成的工作现在由CWinApp的三个函数完成:virtual BOOL InitApplication(); virtual BOOL InitInstance(); virtual int Run();其中CWinApp的handle被移动到其父类CWinThread中,相关的是:m_pMainWnd与m_pActiveWnd
CFrameWnd--取代WndProc的地位,消息映射之类都发生在CFrameWnd中
最后整理如下:
1 程序的诞生
n Application object 产生,内存于是获得配置,初值也设立了,也就是CWinApp theApp
n AfxWinMain执行AfxWinInit,后者调用AfxInitThread,把消息队列尽量加大到96?????
n AfxWinMain执行InitApplication。这是CWinApp虚函数,一般不改写.
n AfxWinMain执行InitInstance.这是CWinApp虚函数,我们必须改写.
n CWinApp::InitInstance new了一个CFrameWnd对象.
n CFrameWnd构造函数调用了Create,产生主窗口。我们在Create参数指定的窗口类是NULL, MFC根据窗口种类,自动为我们注册一个名为’AfxFrame42d’或’AfxView42d’.其中的PreCreateWindow发生在产生窗口之前,为改变窗口外观所用.
n 回到InitInstance中继续执行ShowWindow,显示窗口。
n 执行UpdateWindow,于是发出WM_PAINT
n 回到AfxWinMain,执行Run,进入消息循环.
2程序开始运行l 程序获得WM_PAINT消息(即由CWinApp::Run中的::GetMessage循环)
l WM_PAIN经由::DispathMessage送到窗口过程函数CWnd::DefWindowProc中
l CWnd::DefWindowProc将消息传递过消息映射表格(Message Map)
l 传递过程中发现有相符项目,于是调用项目中对应函数。此函数是应用程序利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的宏设立起来的
l 标准消息的处理程序都有标准命名,WM_PAINT必定由OnPaint处理。其它消息是命令消息EX:ON_COMMAND(IDM_FILENEW,OnFileNew),通告消息,和具体的控件相关.EX: ON_BTN_CLICKED(,)
3 程序的死亡
u 使用者单击file—close,于是发出WM_CLOSE
u CFrameWnd并没有设置WM_CLOSE处理程序,于是交给默认处理程序
u 默认函数对于WM_CLOSE的处理方式是调用::DestroyWindow,并因此发出WM_DESTROY
u 默认的WM_DESTROY,处理方式是调用::PostQuitMessage,发出WM_QUIT
u CWinApp::Run收到WM_QUIT后结束其内部消息循环,然后调用ExitInstance,这是CWinApp的一个虚拟函数
u 如果CWinApp改写了ExitInstance,那么CWinApp::Run 所调用的就是该函数
u 最后回到AfxWinMain,执行AfxWinTerm,结束程序
关于神秘的CALL BACK函数
凡是由你设计而却由Windows系统调用的函数,通称为callback函数。某些API函数会要求以callback函数作为其参数之一。通常这些API会在进行某种行为之后或满足某种状态之时调用该callback函数.
由于CALLBACK函数是由系统调用的,系统并不知道实例化对象的this指针,所以要实现这样一个功能(近似于static静态函数),就需要一个这样特殊的用法。不直接用static 的原因是static在类没产生前就可以用,不合适
-
纵观MFC类,数据类型 - [VC]
2007-02-14
纵观MFC类
1. General Purpose classes :字符串处理,数据处理,异常处理,文件类
具体相关CObject;CArray,CList,CMap;CRect,CSize….;CException
2. Windows API class:封装Windows API, 窗口类,对话框类
相关:CWinThread;CWinApp(派生自CWinThread,内含m_szExeName, ProcessShellCommand);CWnd(凡是派生自CWnd的类才能收到WM_XXX,并拥有m_hwnd);CCmdTarget(CWnd父类,派生自它的的类方能接受WM_COMMAND,该类是消息映射及命令传递的关键)
3. Application frame class :应用程序骨干,Document/View,消息映射,传递,文件读写
重要的是文档类与视类的分离,CDocument/CView.注意一下,MDI与SDI,不同于CMultiDocTemplate与DSignleDocTemplate.
CDocument中最重要的是虚函数Serialize,CView类中最重要的是虚函数OnDraw
4. High level abstractions:工具栏,状态栏…
5. operation system extrensions:OLE、ODBC、WinSock等
C++不是纯种面向对象的语言,MFC中存在有不属于任何类的全局函数,以Afx开头MFC中大多定义的类型都是32bit有:COLORREF,DWORD,LPARAM,WPARAM,LPCSTR,LPSTR.LPTSTR,LPVOID,LPRESULT,UINT,WNDPROC
由于DWORD为32bit,故WORD为16bit
顺便吧C++中其它数据类型的大小也列下
8 double 4 int ,float,long(也包括uint,ulong) 2 short 1 bool,char(unsigned char)
-
今天很简单的看了下第三章,传说中很经典的MFC六大仿真,说实话兴趣不是很大,本来这种内核的东西,我就不是想搞得太清楚,太明白,很多东西孙鑫那也见到过。不过还是总结下
1 MFC类层次结构
这个在MSDN中有个大表,画得很清楚了,下面列出最重要的部分:
2 MFC程序初始化过程
两个相关的函数是全局对象theApp->InitInstance()和InitApplication(),尤其是前者
,有关于窗口设计的部分放在PreCreateWindow()中(PS:PreCreateWindow()最终被InitInstance()中,动态创建MainFrame时候的构造函数所调用)
3 RTTI运行时候的标识符号
这个以前孙鑫应该是没有提到这个概念,注意下.主要这种机制是用于判断对象的类型。用途如下:pMyDoc->IsKindOf(CMydoc); //TRUE pMyDoc->IsKindOf(CDocumet); //TRUE
为了实现这个功能,系统建立了一个CRuntimeClass链表,CRuntimeClass中比较重要的数据成员是1.m_pBaseClass,表示继承关系 2.m_pNextClass,表示链表的结构,顺序.
后来又涉及到两个宏DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC,大概的作用是,声明和实现所创建的链表中的每个类.感觉就其作用而言,就和定义函数模版差不多.
链表的数据结构把它叫做"类别型录网".
4 动态创建
作用是动态创建在执行时候才知道的类型的对象
与此相关的是DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE两个宏,其中DECLARE_DYCRATE包括了RTTI中的DECLARE_DYNAMIC中的相关内容,相比之下,多的是一个m_pfnCreateObject.其指向CreateObject()
把类的大小和其构造函数(就是CreateObject())记录在RTTI创建的类别型录中,这样就构成了一个比较完整的"类别型录网",当程序在执行期间获得一个类名称,它就可以在这个网中找出对应的元素,然后调用构造函数(就是CreateObject(),并不是指C++的构造函数),产生的对象.
最终在”类别型录网”中的类,凡是m_pfnCreateObject不为NULL者,即可动态创建.
永久保存(Persistence) ,就是MFC中一个很重要的Serialize 机制.其中还涉及到一个archive,是一个与文件息息相关的缓冲区,想象为文件的化身,与此相关的两个宏是DECLARE_SERIAL和IMPLEMENT_SERIAL,主要是重载<<和>>.
Load()和Store()也是需要用于读取和保存文件名等.如同下图Serialize调用顺序,我们要做的就是分别去设计CStroke,CRectangle,CCircle的Serialize的函数.
5 Message Mapping(消息映射)
按照以前孙鑫所说,其由3个部分构成,1 .h文件中的afx_message_....的消息声明2消息映射表中,写在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP.格式是ON_COMMAND(ID_MSGNAME,Funcname)注意结为没有分号 3 Funcname()函数的实现
其原理是建立了一张AFX_MSGMAP的结构体
DECLARE_MESSAGE_MAP()中重要函数是:AFX_MSGMAP_ENTRY _messageEntries[] _messageEntries是一个记录消息各种信息的结构体,这样一个数组就是存放了各种消息.这AFX_MSGMAP表的填充又是利用3个宏定义函数BEGIN_MESSAGE_MAP ,ON_COMMAND,END_MESSAGE_MAP,最终把消息的每个标识型如:112 1122和各个类具体函数关联起来
6 命令传递(Command Routin)
1) WM_XXX(WM_CHAR)等windows消息,则一定是从派生类流向基类.不旁流
2) WM_COMMAND
Frame View->Frame->CWinApp
View View->Document
Document Document->Document Template 直到截获为止
-
VC++基类,派生类,虚函数 对象实现 - [VC]
2007-02-11
有关基类,派生类,虚函数
三个结论
/////////////////////////////
假设有:
class CBase--->class CDerived
BaseFunc() DeriFunc()
Communc() Communc()
/////////////////////////
1.如果你以一个"基类之指针"指向"派生类之对象",那么经由该指针你只能够调用基类所定义的函数.
虽然我们可以令pBase实际指向Cderived对象,却因为pBase得类型,使他只能够调用BaseFunc(),不能调用DeriFunc().
CBase *pBase;
CDerived aDerive("Rukocy");
*pBase = &pDerived;//right,一个Derived对象一定是Base类,但其只能调用BaseFunc()2.如果你以一个"派生类之指针"指向一个基类的对象",你必须先做明显的转型操作(explicit cast).这种做法很危险,不符合现实生活经验.
CDerived *pDeri;
CBase aBase("Jason");
pDeri = &aBase;//这样写有问题!一个Base的对象不一定是CDerived3.如果基类和派生类都定义了"相同名称之成员函数",那么通过对象指针调用成员函数时,到底调用那一个函数,必须视该指针的原始类型而定,而不是视指针实际所指的对象的类型而定
pBase->Communc() //永远指向CBase::Communc()
pDerived->Communc()//永远指向CDerived::Communc()PS:从此需要满足多态性,引入了虚函数
如果你以一个基类之指针指向一个派生类之对象,那么通过设定其为虚函数,你就调用派生类的成员函数,按照孙鑫习惯性的描述:虚函数--子类有调用子类的,子类没有调用父类的!
MFC中两个十分重要的虚函数:CDocument 有关的Serialize()与和CView有关的OnDraw()
CObject--->CDocument--->CMyDoc
CMyDoc mydoc;
CMyDoc *pmydoc = new CMyDoc;
mydoc.func() == ((CDocument*)&mydoc)->func() == pmydoc->func()
但是((CDocument)mydoc).func()不同于上面三者,调用的是基础类的虚函数,并没有实现我们预期的多态,这种性质是因为其转换的是整个对象,不是指针,并且被截断了.同时,(CMyDoc)cdocument这样的转换是不允许的.
有关对对象的几种实现方式:
1 对于全局对象,程序一开始,其构造函数被执行,比main函数还要早;程序即将结束前调用析构函数
在MFC中有个global的theapp
2 对于局部对象,略
3 对于静态对象,如static CString str("abcd");对象诞生时构造,程序结束时候析构,但是比全局对象更早一步
4 对于以new方式产生出来的局部对象,诞生时候构造,析构在delete时候,即使程序结束时也不会调用析构.
对应四种对象生存方式in stack/in heap/global/local static -
函数调用习惯,WIN32程序过程,LPCTSTR - [VC]
2007-02-10
函数调用习惯(Calling conventions)
函数调用习惯所决定的有:函数参数进栈的次序;调用结束后,是调用者还是被调用者来清除栈里的参数;编译器修饰名字的方式。
1. __cdecl. 函数参数从右向左传递,调用者清除栈中参数(因此产生的代码较大)。C语言编译时在函数名前加下划线,不做大小写转换,C++跟C不同,所以调用C库函数时要在extern "C"块中声明,告诉编译器用C的方式来修饰名字。这是C/C++的默认调用方式,用这种调用方式的一个好处是可以编写可变参数个数的函数。
但在x86中,C++的成员函数一般将this指针放在寄存器ECX中,其他参数从右向左传递,被调用者清除栈。如果某类的一个成员函数要作为可变参数个数的,则需要用__cdecl来修饰(其实只要有可变参数,编译器就自动认为是__cdecl)。MFC中的CString::Format是一个例子。2. __stdcall. 被调用者清除栈。编译器生成的修饰过的函数名为_func@number,number指参数的总byte数。
3. __fastcall. 前两个DWORD参数被放入ECX、EDX,其他从右至左传递。被调用者清除栈。生成函数名为@func@number。
4. __pascal等调用方式不再被微软的编译器支持。
在Win32 API中,WINAPI,APIPRIVATE和CALLBACK都定义为__stdcall,而APIENTRY和WINAPI又是一个东西。
PS:CALLBACK函数意思是:在你的程序中,被windows系统调用.这些函数虽然由你设计,但是永远不会,也不应该被你调用,它们就是为windows准备的.
??堆栈的概念不明!
WIN32程序过程
1.设计窗口类
WNDCLASS wc;
wc.....=....
2 注册窗口类
RegisterClass(&wc);
////////////////////
3 产生窗口实例
HWND hWnd;
hWnd=CreateWindow(......)
4 显示窗口
ShowWindow()
5 送出 WM_PAINT消息
UpdataWindow()
6 消息循环,转换键盘消息
TranslateMessage(&msg);
7 消息循环,分派消息,传递给窗口处理
DispatchMessage(&msg);
如何理解LPCTSTR类型?
L表示long指针
这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32为操作系统中,long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。P表示这是一个指针
C表示是一个常量
T表示在Win32环境中, 有一个_T宏.
这个宏用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串, 否则就是标准的ANSI字符串。STR表示这个变量是一个字符串.
所以LPCTSTR就表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。同样,LPCSTR就只能是一个ANSI字符串, 在程序中我们大部分时间要使用带T的类型定义。PS:
1 LPCTSTR == const TCHAR *,也就是说(LPCTSTR)str的方法应该等同于str.c_str()
2 但是如果要把一个CString转化为char *的方法,最佳方案是调用str.GetBuffer(i)P55
-
有点放晕,记录下
消息的分类:标准消息,命令消息,通告消息。
[标准消息]:除WM_COMMAND之外,所有以WM_开头的消息。
[命令消息]:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。
在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。
[通告消息]:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。
说明:
1)从CWnd派生的类,都可以接收到[标准消息],[命令消息]和[通告消息]。
2)从CCmdTarget派生的类,都可以接收到[命令消息]和[通告消息]。 -
据说blogbus更新了,不用发布了,速度又不错,于是决定重写blog.......不知道这次会坚持多长时间:)
还有20天不到了,考研迫在眉睫,复习的效果依然不如人意。我会努力用好最好的这10几天,希望依然存在,加油,尽力而为,相信这是最重要的
还有一点要告诫自己,一定要按时睡觉,中午1点,晚上12:30







