6.3.2 实现多态
怎么能够实现多态呢?当前,动态对象是在入口函数中创建的,而按照现有逻辑,入口函数是不允许修改的。笔者要提供一个机会,让库使用者可以创建动态对象。为此笔者特地有一个规定,所有库使用者必须定义一个宏,以注册自己的驱动类。
- REGISTER_DRV_CLASS(DriverName)
如果不使用子类,则需要定义下面的宏而直接使用基类。
- REGISTER_DRV_CLASS_NULL()
那么这两个宏到底有什么作用呢?要看宏定义了:
- // 注册子类
- #define REGISTER_DRV_CLASS(DriverName) \
- DrvClass* GetDrvClass(){\
- return (DrvClass*)new(NonPagedPool, '10YC') DriverName();\
- }
-
- // 注册基类
- #define REGISTER_DRV_CLASS_NULL()\
- DrvClass* GetDrvClass(){\
- return new(NonPagedPool, 'ESAB') UsbBaseClass();\
- }
两个宏都是为了定义一个名称为GetDrvClass的函数。前者注册驱动类的子类,并在GetDrvClass的实现中动态创建子类对象,在返回时将子类对象的指针转换为基类对象指针;后者则声明直接使用基类,并在GetDrvClass的实现中动态创建一个基类对象,并返回其指针。
调用者不必关心被创建的对象到底是来自基类还是子类,他只要使用在基类中定义的接口就可以了,而借助虚拟函数的运行时绑定策略,即可实现多态。
需要注意的是宏REGISTER_DRV_CLASS(DrvClass),其作用和REGISTER_DRV_ CLASS_NULL()是一样的,都将定义一个GetDrvClass函数。
好戏还要看DriverEntry()函数中的实现,重新修改后的函数代码如下:
- NTSTATUS Driver(DRIVER_OBJECT Driver,
- UNICODE_STRING Register)
- {
- DrvClass* pDriver = GetDrvClass();
- return pDriver->DriverEntry(Driver, Register);
- }
真是无与伦比的简洁,它通过GetDrvClass函数实现了多态,并立刻将驱动的实现交付到了pDriver对象的手中,而pDriver可以是基类,也可以是任意一个从基类继承的子类。
实现多态的核心是两个类注册宏,以及在入口函数中对GetDrvClass函数的调用。需要注意的是,如果用户同时定义了两个宏,那么系统就会因为发现两个完全一样的GetDrvClass函数而使编译失败;反之,如果上述两个宏一个都没有定义,那么在链接时,将因为无法找到函数定义而链接失败。
驱动工程UsbBaseClass使用驱动基类直接驱动CY001 USB设备,从SOURCE文件中可以看到,它含有的编译文件为DrvClass.cpp和GetDrvClass.cpp两个文件,前者是基类的定义文件,后者只有一行代码,即REGISTER_DRV_CLASS_NULL()。这是最简单的驱动工程。
驱动工程CY001USBClass使用驱动子类CY001DrvClass驱动CY001 USB设备,从SOURCE文件中可以看到,它依旧包含了DrvClass.cpp文件,此外还包含了若干个子类的实现文件。
所以,读者只要在DrvClass甚至CY001DrvClass类的基础上实现子类化,并注册新的子类,就能够实现功能扩展。
如图6-6所示是本节所讲的多态实现原理图。
|
| (点击查看大图)图6-6 多态关系图 |