cocos2dx 入口分析

为了理解多态的进一步应用,老师带着我们简单分析了一下cocos2dx的入口,深刻的体会到了虚函数和类静态成员变量的作用。以此给大家分享一下这个过程。

打开cocos2dx的main.cpp文件,我们可以看到如下代码:

2015-05-17_191143

#include "main.h"
#include "AppDelegate.h"
#include "CCEGLView.h"
 
USING_NS_CC;
 
int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // create the application instance
    AppDelegate app;
    CCEGLView* eglView = CCEGLView::sharedOpenGLView();
    eglView->setViewName("cocos2dx");
    eglView->setFrameSize(480, 320);
    return CCApplication::sharedApplication()->run();

}

其中,AppDelegate 上方有一段注释,提示创建应用程序实例。随后加载了 OpenGL 的库,最后一句 return 返回了 CCApplication 的一个成员函数的返回值,其中最重要的两句就是创建了 AppDelegate app 对象以及最后一句 return 所调用的 run() 函数,他们中间利用多态的概念成功的开辟了一个程序的入口点。

下面我们先分析一下 AppDelegate 类的结构。

2015-05-17_191943

AppDelegate 类继承了 CCApplication 类,而且我们可以看到,继承的权限是 private 的。也就是说,他没有继承任何父类的资源,但是其内部实现了几个方法,这几个方法全部是继承下来的虚函数,并且在 AppDelegate  类中均做了实现:

virtual bool applicationDidFinishLaunching();
virtual void applicationDidEnterBackground();
virtual void applicationWillEnterForeground();

其中最重要的一个就是 applicationDidFinishLaunching() 方法,后面你将看到他的面目。

因 AppDelegate的父类是 CCApplication 类,所以在实例化一个 AppDelegate 对象时会调用 CCApplication 类的构造器,那么接下来我们看一下CCApplication 类的构造器。

CCApplication::CCApplication()
: m_hInstance(NULL)
, m_hAccelTable(NULL)
{
    m_hInstance    = GetModuleHandle(NULL);
    m_nAnimationInterval.QuadPart = 0;
    CC_ASSERT(! sm_pSharedApplication);
    sm_pSharedApplication = this;
}

构造器最后一句便是将一个将 sm_pSharedApplication 变量设置为 this;也就是说,当这个类有对象实例化时,则把这个对象的指针付给 sm_pSharedApplication 变量,但是此时你会发现,CCApplication 类是从CCApplicationProtocol 类中继承下来的,CCApplicationProtocol 类是一个抽象类,包含有多个纯虚函数,在CCApplication 类内部并没有对这些纯虚函数进行实现,所以当前 CCApplication 类也是一个抽象类,无法被实例化的。这里把 this 赋值给 sm_pSharedApplication 有什么意义吗?

在考虑这个问题之前,回想一下之前实例化的 AppDelegate的对象,该类构建时会调用父类 CCApplication 类的构造器,换个角度说,CCApplication 类无法实例化对象,但其子类是可以实例化对象的,并且其子类继承了CCApplication 类所有没有实现的纯虚函数并做了实现。在实例化对象时,这个 this 就指向了我们在main函数中看到的 app 对象。过程如下图:

2015-05-17_200151

此时 this 指向实例化的对象 app ,在 CCApplication 类的构造器中,将该指针赋值给了 sm_pSharedApplication 。在 CCApplication 类的成员中,我们找到了 sm_pSharedApplication 成员,他被声明为一个 static 变量,也就是在整个应用程序中,它都是有效的,得到这个结论后,我们知道了以下信息。
1、 AppDelegate 类继承了CCApplication 类并实现了所有从 CCApplicationProtocol 类中继承下来的纯虚函数。
2、当实例化一个 AppDelegate 类的对象时,调用了 CCApplication 类的构造器,将 AppDelegate 对象的指针赋值给了一个 CCApplication 类的静态的成员变量 sm_pSharedApplication。

接下来,我们再来分析最后一步:

return CCApplication::sharedApplication()->run();

首先调用了 CCApplication 类的成员方法 sharedApplication(),该方法实现如下:

CCApplication* CCApplication::sharedApplication()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}

它只是获取了一下静态变量 sm_pSharedApplication 的值并返回。返回后再次调用了 CCApplication 类的方法 run(),在 run() 中,调用了由 AppDelegate 类实现的方法 applicationDidFinishLaunching():

// Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())
{
    return 0;
}

回想一下多态实现的三个条件。
1,是父类中有虚函数。(CCApplicationProtocol 类中多个纯虚函数)
2,子类 override(覆写)父类中的虚函数(AppDelegate 类覆写了所有纯虚函数)
3,通过己被子类对象赋值的父类指针,调用共用接口(利用静态变量 sm_pSharedApplication 做中介将AppDelegate 实例化的对象指针通过 this 的方式存放到 sm_pSharedApplication 中,最后借用成员函数 run() 调用了共用接口 applicationDidFinishLaunching())

以上便是coco2dx利用多态的特性构建的一个程序入口。不得不感叹真的是把C++玩飞了。

评论