为了理解多态的进一步应用,老师带着我们简单分析了一下cocos2dx的入口,深刻的体会到了虚函数和类静态成员变量的作用。以此给大家分享一下这个过程。
打开cocos2dx的main.cpp文件,我们可以看到如下代码:
#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 类的结构。
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 对象。过程如下图:
此时 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++玩飞了。