在/frameworks/base/services/input/eventhub.h声明了eventhub类,在该类的私有成员中嵌套声明了device 结构体,如下:
private:
structDevice {
Device*next;
int fd;// may be -1 if device is virtual
constint32_t id;
constString8 path;
constInputDeviceIdentifier identifier;
uint32_t classes;
uint8_tkeyBitmask[(KEY_MAX + 1) / 8];
uint8_tabsBitmask[(ABS_MAX + 1) / 8];
uint8_trelBitmask[(REL_MAX + 1) / 8];
uint8_tswBitmask[(SW_MAX + 1) / 8];
uint8_t ledBitmask[(LED_MAX + 1) / 8];
uint8_tffBitmask[(FF_MAX + 1) / 8];
uint8_tpropBitmask[(INPUT_PROP_MAX + 1) / 8];
String8configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
KeyMap keyMap;
sp<KeyCharacterMap>overlayKeyMap;
sp<KeyCharacterMap> combinedKeyMap;
boolffEffectPlaying;
int16_tffEffectId; // initially -1
Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier&identifier);
~Device();
voidclose();
inlinebool isVirtual() const { return fd < 0; }
constsp<KeyCharacterMap>& getKeyCharacterMap() const {
if(combinedKeyMap != NULL) {
return combinedKeyMap;
}
return keyMap.keyCharacterMap;
}
};
1.在该结构体中声明了内联函数inlinebool isVirtual() const { return fd < 0; }。
2.在该结构体中定义了一个两个指向KeyCharacterMap类的强指针.
Android中定义了两种智能指针类型,一种是强指针sp(strongpointer),一种是弱指针(weakpointer)。其实成为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。
弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先将弱指针升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。
是不是很神奇?弱指针是怎么做到这一点的呢?其实说穿了一点也不复杂,原因就在于每一个可以被智能指针引用的对象都同时被附加了另外一个weakref_impl类型的对象,这个对象中负责记录对象的强指针引用计数和弱指针引用计数。这个对象是智能指针的实现内部使用的,智能指针的使用者看不到这个对象。弱指针操作的就是这个对象,只有当强引用计数和弱引用计数都为0时,这个对象才会被销毁。
如上面,要使用智能指针来引用KeyCharacterMap类的对象,那么这个类需满足下列两个前提条件:
(1)这个类是基类RefBase的子类或间接子类;
(2)这个类必须定义虚析构函数,即它的析构函数需要这样定义:
virtual~KeyCharacterMap();
该device的构造函数在/frameworks/base/services/input/eventhub.cpp文件中定义,如下:
EventHub::Device::Device(intfd, int32_t id, const String8& path,
const InputDeviceIdentifier&identifier) :
next(NULL),
fd(fd), id(id), path(path),identifier(identifier),
classes(0), configuration(NULL),virtualKeyMap(NULL),
ffEffectPlaying(false), ffEffectId(-1){
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
memset(swBitmask, 0, sizeof(swBitmask));
memset(ledBitmask, 0, sizeof(ledBitmask));
memset(ffBitmask, 0, sizeof(ffBitmask));
memset(propBitmask, 0,sizeof(propBitmask));
}
1. 在构造函数后面使用冒号给类成员变量进行赋值,初始化列表,更适用于成员变量的常量const型。类构造函数(Constructor)的初始化列表有以下几点:
1) 初始化列表的作用相当于在构造函数内进行相应成员变量的赋值,但两者是有差别的。
在初始化列表中是对变量进行初始化,而在构造函数内是进行赋值操作。两都的差别在对于像const类型数据的操作上表现得尤为明显。我们知道,const类型的变量必须在定义时进行初始化,而不能对const型的变量进行赋值,因此const类型的成员变量只能(而且必须)在初始化列表中进行初始化。
2) 初始化的顺序与成员变量声名的顺序相同。
3) 对于继承的类来说,在初始化列表中也可以进行基类的初始化,初始化的顺序是先基类初始化,然后再根据该类自己的变量的声明顺序进行初始化。
2. 结构体和类的区别:
结构是一种用关键字struct声明的自定义数据类型。与类相似,也可以包含构造函数,常数,字段,方法,属性,索引器,运算符和嵌套类型等,不过,结构是值类型。
1)结构的构造函数和类的构造函数不同。
a.结构不能包含显式的无参数构造函数。结构成员将自动初始化为它们的默认值。
b.结构不能包含以下形式的初始值设定类:base(argument-list);
2).对于结构中的实例字段成员,不能在声明时赋值初始化。
3)声明了结构类型后,可以使用new运算符创建构造对象,也可以不使用new关键字。如果不使用new,那么在初始化所有字段之前,字段将保持未赋值状态且对象不可用。
4)结构不支持继承,即一个结构不能从另一个结构或类继承,而且不能作为一个类的基类。但是,结构从基类OBJECT继承。结构也可以实现接口。
5)什么时候用结构呢?结构使用简单,并且很有用,但是要牢记:结构在堆栈中创建,是值类型,而类是引用类型。每当需要一种经常使用的类型,而且大多数情况下该类型只是一些数据时,使用结构能比使用类获得更佳性能。