• c++多态的实现 VC++消息映射的实现


    http://blog.csdn.net/gxnu/archive/2007/09/26/1801870.aspx

    多态是如何利用这个虚函数表实现的呢?看下面的代码:

    struct Super

    {

         int data;

         virtual int add(int i){return i;};

         virtual string toString()=0;

    };

    class Sub: public Super

    {

    public:

         string toString()

         {

             return string("Sub class");

         }

    };

     

         Super* s = new Sub();

         cout<<s->toString()<<endl;

         delete s;

    输出”Sub class”


    VC++消息映射的思考

    作者:郝庆欣

    在学习VC++的时候,大家都不可避免的用到消息映射。我们都知道C++是一种面向对象的编程语言,VC++中为什么这样来实现消息映射呢?
      首先要明白一个包含了消息处理的Windows程序是如何工作的。
      一般来说一个包含了消息处理的Windows程序至少要包含两个函数
       第一个:
        int WINAPI WinMain(
          HINSTANCE hInstance,   // handle to current instance
          HINSTANCE hPrevInstance,  // handle to previous instance
          LPSTR lpCmdLine,     // command line
          int nCmdShow     // show state
        );
       第二个:
       long FAR PASCAL WndProc(HWND hWnd,WORD message,WORD wParam,LONG lParam);
       我们不必纠缠程序实现的细节,

    只要明白在第一个函数WinMain中要注册WndProc函数,通俗一些的理解就是WinMain告诉Windows系统,听着,我知道你要产生很多消息,我这里有一个WndProc函数负责处理你传递来的各种消息。当然消息的格式都是系统规定好的。

    其次要明白C++中是如何实现多态性的。

    我们知道多态性实现的关键是晚绑定(或者称为后期绑定),其实质就是编译器并没有在编译期间指定调用函数的绝对地址,而是指定了某个类内部该函数的偏移地址。

    为了实现上面的功能,编译器为我们作了手脚

    1、  在每个带有虚函数的类中,编译器秘密放置了一个指针,称为Vpointer

    2、  当系统运行时,

    为每个类创建一个VTABLE,其中包含了可以调用虚函数地址。

    3、  Vpointer出始化,指向VTABLE,通过在Vtable中偏移,来找到正确的需要调用的函数地址。

    然后是MFCWindow API进行的封装

    当我们利用MFC框架开发程序的时候,尤其是开发界面应用程序的时候,必定要用到CWnd或者派生于CWnd的类。根据面向对象的设计原则,对于CWnd的一些通用函数,例如窗口大学改变(OnSize,窗口移动(OnMove),最好是在CWnd中声明为虚函数,然后在继承的类里面重载他们。但是,这样以来,每个相关的派生类都要有一个Vpointer和一套记录Vtable,CWnd中通用函数是如此至多,CWnd的派生类也很多,必然会导致系统在运行是占用过多的资源(内存),这样显然是不合适的。

     

    那么MFC是如何实现的呢?

    答案就是在CWnd基类中尽可能的少用虚函数,采用消息映射机制来代替。

    大家可以看一下CWnd的类中的函数,就会发现这一点。

    CWnd::OnMove 

    afx_msg void OnMove( int x, int y );

    上面这个函数就不是虚函数。

     最后的问题消息映射是如何实现的呢?

     用一句话说,就是利用宏定义来实现面向过程的消息处理。

    例如在VC中有如下的消息映射宏。

    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)  //{{AFX_MSG_MAP(CMainFrame)

    ON_WM_CREATE() 

    //}}AFX_MSG_MAP

    ON_COMMAND(ID_FONT_DROPDOWN, DoNothing)

    END_MESSAGE_MAP()

    经过编译后,代码被替换为如下形式(这只是作讲解,实际情况比这复杂得多):

    //BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 

    CMainFrame::newWndProc(...)

    {

    switch(...)

    {

    //{{AFX_MSG_MAP(CMainFrame)

    // ON_WM_CREATE() 

    case(WM_CREATE):

    OnCreate(...);

    break;

    //}}AFX_MSG_MAP

    // ON_COMMAND(ID_FONT_DROPDOWN, DoNothing)

    case(WM_COMMAND):

    if(HIWORD(wP)==ID_FONT_DROPDOWN)

    {

    DoNothing(...);

    }

    break;

    //END_MESSAGE_MAP()

    }

    }

    这样,

    VC++就消除了对部分虚拟函数的需要,从而节省了内存空间。

     

    参考资料:

      Thingking in C++,Bruce Eckel;

      http://www.vchelp.net/  闻怡洋

      寒岩之上,唯我独行---小朱

  • 相关阅读:
    偏函数
    通过local对象的使用,分析flask中全局request对象为神魔不同的视图函数中不会混乱--协助解读flask的源码
    flask安装即web框架介绍
    事件
    文件复制工具
    非文本文件的写入
    文件读取
    sys模块
    datetime模块
    事件冒泡与捕获
  • 原文地址:https://www.cnblogs.com/cutepig/p/920873.html
Copyright © 2020-2023  润新知