荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: [转载] MFC类中获得其它类指针
发信站: 荔园晨风BBS站 (Sat Jul 21 08:39:43 2001), 转信

mfc类中获得其它类指针成都:苏颖锋

(vcmfc输入并转贴)  当用vc++的application wizard生成除了cdialog basiced以外的
应用程序时,将自动产生视图类、文档类、主帧窗口类、应用程序类等等。一般来说,
程序的核心数据及操作在文档类中实现。跟界面有关的数据及操作在视图类中实现。当
需要在某个类中使用不属于该类的数据时,必须要取得该数据所属类的指针。从视图类
获得文档类的指针是很容易的,用getdocument即可,这在一般的mfc文档中有介绍,也
是编程中极为常用的的操作,比如视图类在进行重画等操作时,往往要用到文档类中的
数据。然而只能从视图类获得文档类的指针是远远不够的,每个类都有获得其它各个类
指针的一套方法,现归纳如下:  为方便说明,现假设已用application wizard生成一
个sdi应用程序test,包含如一几个类:ctestapp,ctestdoc,ctestview,cmainfrm.1.从
视图类获得文档类的指针  如前所述,在视图类中需要引用文档类的地方之前,使用以
下语句:
 ctextdoc *pdoc=(ctestdoc*)getdocument();
以后便可使用pdoc指针访问文档类。

此处的强制类型转换在test应用程序中并不必需,因为该程序中只有一个视图类,并且
在initstance()中用sdi文档模板进行了装配,你可以在test.cpp中的initstance()方法
中看到以下语句:
    csingledoctemplate *pdoctemplate;
    pdoctemplate=new csingledoctemplate(idr_mainframe,runtime_class(ctestdoc
),runtime_class(cmainframe),
        runtime_class(ctestview));
    adddoctemplate(pdoctemplate);
    以及testview.h中的线上定义:
    inline ctestdoc* ctestview::getdocument()
    { return (ctestdoc*)m_pdocument;}

  简而言之,就是说ctestview的getdocument()函数自然而然地认为ctestdoc是与它“
相配”的,当生成了一个具有多个视图类的应用程序时(如用csplitterwnd)将窗口分为
两栏,但这两栏并非从同一种视图类派生就属于这种情况。具体实现在本文讨论范围之
外),只有一个视图类能与唯一的文档类用文档模板进行装配,那么在另外一个未经装
配的类中要取得文档类的指针,则需时行强制类型转换。2.从文档类取得视图类的指针
    cdocument类提供了两个函数用于视图类的定位:getfirstviewposition()和getne
xtview(),具体语法如下:
    virtual position getfirstviewposition() const;
    virtual cview* getnextview(position& rposition) const;

    注意:getnextview()括号中的参数用的是引用方式,因此执行后值可能改变。

    getfirstviewposition()用于返回第一个视图位置(返回的并非视图类指针,而是
一个position类型值),getnextview()有两个功能:返回下一个视图类的指针以及用引
用调动的方式来改变传入的position类型参数的值。很明显,在test程序中,只有一个
视图类,因此只需将这两个函数调用一次即可得到ctestview的指针如下(需定义一个p
osition结构变量来辅助操作):
    ctestview* ptestview;
    position pos=getfirstviewposition();
    ptestview=getnextview(pos);

这样,便可到了ctestview类的指针ptestview.执行完成几句后,变量pos=null,因为没
有下一个视图类,自然也没有下一个视图类的position.但是之几条语句太简单,不具有
太强的通用性和安全特征;当象前面说的那样,当要在多个视图为中返回某个指定类的
指针时,我们需要遍历所有视图类,直到找到指定类为止。判断一个类指针指向的是否
某个类的实例时,可用iskindof()成员函数时行检查,如:
    pview->iskindof(runtime_class(ctestview));

    即可检查pview所指是否是ctestview类。
有了以上基础,我们已经可以从文档类取得任何类的指针。为了方便,我们将其作为一
个文档类的成员函数,它有一个参数,表示要获得哪个类的指针。实现如下:
    cview* ctestdoc::getvieww(cruntimeclass* pclass)
    {  cview* pview;
        position pos=getfirstviewposition();
        while(pos!=null){
        pview=getnextview(pos);
        if(!pview->iskindof(pclass))
            break;}
        if(!pview->iskindof(pclass)){
            afxmessagebox("connt locate the view.");
            return  null;}
        return pview;}

    其中用了两次视图类的成员函数iskindof()来判断,是因为退出while循环有三种可
能:
    1.pos为null,即已经不存在下一个视图类供操作;
    2.pview已符合要求。
    3.1和2同是满足。这是因为getnextview()的功能是将当前视图指针改变成一个视图
的位置同时返回当前视图指针,因此pos是pview的下一个视图类的position,完全有可能
既是pos==null又是pview符合需要。当所需的视图是最后一个视图是最后一个视图类时
就如引。因此需采用两次判断。
    使用该函数应遵循如下格式(以取得ctestview指针为例):
    ctestview* ptestview=(ctestview*)getview(runtime_class(ctestview));
    runtime_class是一个宏,可以简单地理解它的作用:将类的名字转化为cruntimec
lass为指针。

    至于强制类型转换也是为了安全特性考虑的,因为从同一个基类之间的指针类型是
互相兼容的。这种强制类型转换也许并不必要,但能避免一些可能出现的麻烦。3.从一
个视图类取得另一视图类的指针    综合1和2,很容易得出视图类之间互相获得指针的
方法:就是用文档类作中转,先用1的方法得到文档类的指针,再用2的方法,以文档类
的视图定位函数取得另一个视图类。同样,可以实现成一个函数:
    (假设要从ctestaview中取得指向其它视图类的指针)
    cview* ctestaview::getview(cruntimeclass* pclass)
    {    ctestdoc* pdoc=(ctestdoc*)getdocument();
        cview* pview;
        position pos=pdoc->getfirstviewposition();
        while(pos!=null){
        pview=pdoc->getnextview(pos);
        if(!pview->iskindof(pclass))
            break;}
        if(!pview->iskindof(pclass)){
            afxmessagebox("connt locate the view.");
            return  null;}
        return pview;}
    这个函数和2中的getview()相比,一是多了第一句以取得文档类指针,二是在getf
irstviewposition()和getnextview()前加上了文档类指针,以表示它们是文档类成员函
数。

    有了此函数;当要从ctestaview中取得ctestbview的指针时,只需如下:
    ctestbview* ptestbview=(ctestview*)getview(runtime_class(ctestbview));4.
 从主帧窗口类获得视图类指针    对本文所举的test这各sdi程序来说,这是简单
的,只需用cframewnd类的getactiveview()成员函数即可。格式如下:
    cframewnd::getactiveview()

    但将此函数应用在mdi应用的cmdiframewnd为中时,并不象所想的那样获得当前活动
子窗口的视图类,而是返回null,这是一个要领性问题。在mdi程序中,cmdiframewnd没
有和任何视图类发生关系,也就是说没有视图类直接属于它,只有子帧窗口类cmdichil
dwnd才是所有子窗口视图类的父窗口。而子帧窗口的父窗口才是cframewnd。因此,在m
di程序中获得活动视图类的正确方法应为:先获得活动子帧窗口,再从活动子帧窗口中
获得活动视图类:
    //获得活动子帧窗口
    cmdichildwnd* pchild=(cmdichildwnd*)getactiveframe();
    //或:cmdichildwnd* pchild=mdigetactive();
    //获得活动子帧窗口的活动视图
    cmyview* pview=(cmyview*)pchild->getactiveview();5.从视图类中获得主帧窗口
类指针:用函数:cwnd::getparentframe()或afxgetmainwnd();
可达到目的。getparentframe()的工作原理是在父窗口链中搜索,直到找到cframewnd或
其派生类为止,并返回其指针。用法在infoviewer中有详细介绍。6.在任何类中获得应
用程序类

    用mfc全局函数afxgetapp()可做到。7.从应用程序类中获得主帧窗口类
    cwinthread类有一个数据成员叫m_pmainwnd,由于cwinapp类由cwinthread派生而来
,我们的应用程序为又由cwinapp派生而来,所以我们的ctestapp类也有一个m_pmainwn
d成员,它所指南的即是cmainframe类。(需进行合适的强制类型转换)。总结起来有几
点注意:
    a.在类a中获得类b的指针时,类a应包含类b的头文件。
    b.在很多时候要进行强制类型转换,并要注意括号的括法。
        由于派生类和父类指针类型的兼容,使明确区分各个类变得十分重要。在拿不
准的时候,最好加上强制类型转换。

--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.28.190]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店