前边分析machine的注册和选择,发现如果 不了解qom系统是很难分析的。
qom系统的说明在include/qom/object.h中。看注释估计是个中国人写的
系统用于创建新的类型和对象,也就是我们在面向对象系统里面说的class,和object, 另外系统还实现了接口继承(可以多继承)。
下面我们来看下qom这个面向对象系统是如何实现的。
首先我们来剖析下面向对象系统的特点。
首先面向对象系统把方法和数据组成一个结构,叫类(class), 类描述的信息有两种
1 数据
2 方法
如何把数据于方法关联起来了,最好的办法就是传参,面向对象语言于面向过程语言的的区别在于方法是不是属于类,其实面向过程也可以实现面向对象,例如下面的例子
class MyClass {
public:
int a;
void setA(int a){
this->a = a;
}
}
要想用面向过程的语言实现上面的类似面向对象功能该如何写呢,如下
typedefine struct MyClass {
int a ;
void (*setA)(MyClass *this, int a);
} MyClass
MyClass myclass;
void setA(MyClass *this, int a) {
this->a = a;
}
myclass.setA = setA;
所以我们要想用c实现一个面向对象的系统,我们需要做到如下几点
1 对于一个class,我们要知道它的具体方法实现,如 MyClass我们要知道它的setA指向哪里。只有这样我们创建的每一个实例才行为一致。
2 对于多态呢 还要保证函数指针的如setA函数的第一个参数必须满足
是MyClass或者MyClass的子类
3 另外对于接口的实现还要保证可以多继承,其实最主要的功能是能将实现类转化为接口。
好了 大概理清了思路,我们就来分析下qom是如何实现的
我们先不管接口实现,先来看看class绑定方法是如何实现的
typedef void (*DeviceReset)(DeviceState *dev);
typedefine struct DeviceClass {
ObjectClass parent_class;
DeviceReset reset;
}
void my_device_class_init(ObjectClass *klass, void *class_data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = my_device_reset;
}
static const TypeInfo my_device_info = {
.name = TYPE_MY_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(MyDevice),
.class_init = my_device_class_init,
};
static void my_device_register_types(void)
{
type_register_static(&my_device_info);
}
type_init(my_device_register_types)
如上type_register_static会将类型注册到类型系统。TypeInfo的class_init的实现为my_device_class_init,从名字可以该处开函数为class初始化的,在这个函数中会将我们的类DeviceClass的成员函数绑定为my_device_reset(用户实现的函数,从而把类方法进行绑定)。
细心的用户还可能注意到DeviceReset的第一个参数为DeviceState,在qom里面确实习惯将一个class的实例写作xxxstate。对于静态函数当然参数应该为xxxclass
看到了方法绑定我们再来分析下如何实现继承。
前面的例子又是细心的读者应该注意到DeviceClass的第一个成员函数为 ObjectClass parent_class, 没错ObjectClass就是它的父类。
我们再来举个例子
struct PCMachineClass {
MachineClass parent_class;
......
}
struct MachineClass {
ObjectClass parent_class;
.......
}
可以看到PCMachineClass继承MachineClass,而MachineClass又继承PCMachineClass,这样就好理解了吧,怎么理解呢,PCMachineClass如何覆盖MachineClass和使用MachineClass的函数呢?object.h的例子里也是有答案的
* typedef struct MyState MyState;
*
* typedef void (*MyDoSomething)(MyState *obj);
*
* typedef struct MyClass {
* ObjectClass parent_class;
*
* MyDoSomething do_something;
* } MyClass;
*
* static void my_do_something(MyState *obj)
* {
* // do something
* }
*
* static void my_class_init(ObjectClass *oc, void *data)
* {
* MyClass *mc = MY_CLASS(oc);
*
* mc->do_something = my_do_something;
* }
*
* static const TypeInfo my_type_info = {
* .name = TYPE_MY,
* .parent = TYPE_OBJECT,
* .instance_size = sizeof(MyState),
* .class_size = sizeof(MyClass),
* .class_init = my_class_init,
* };
*
* typedef struct DerivedClass {
* MyClass parent_class;
*
* MyDoSomething parent_do_something;
* } DerivedClass;
*
* static void derived_do_something(MyState *obj)
* {
* DerivedClass *dc = DERIVED_GET_CLASS(obj);
*
* // do something here
* dc->parent_do_something(obj);
* // do something else here
* }
*
* static void derived_class_init(ObjectClass *oc, void *data)
* {
* MyClass *mc = MY_CLASS(oc);
* DerivedClass *dc = DERIVED_CLASS(oc);
*
* dc->parent_do_something = mc->do_something;
* mc->do_something = derived_do_something;
* }
*
* static const TypeInfo derived_type_info = {
* .name = TYPE_DERIVED,
* .parent = TYPE_MY,
* .class_size = sizeof(DerivedClass),
* .class_init = derived_class_init,
* };
由于父class的数据结构在子class的第一个结构体变量,所以可以将子class直接强制转换为父class。 所以可以在子class_init的时候给父class的成员函数赋值, 这样就实现了多态和抽象类的功能,还可以在子class调用父class的函数。
可想而知,在子class初始化的时候需要执行父class的初始化,然后将父class的数据直接memcpy到子class的parent_class数据域里面。多态的基本功能就算完成了。
所以class_init的函数原型为
void (*class_init)(ObjectClass *klass, void *data);
第一个参数为ObjectClass,这就是c语言里面的多态实现方式吧,很有意思
下面在看看看如何创建实例
* #include "qdev.h"
*
* #define TYPE_MY_DEVICE "my-device"
*
* // No new virtual functions: we can reuse the typedef for the
* // superclass.
* typedef DeviceClass MyDeviceClass;
* struct DeviceState {
/*< private >*/
Object parent_obj;
...
}
* typedef struct MyDevice
* {
* DeviceState parent;
*
* int reg0, reg1, reg2;
* } MyDevice;
*
* static const TypeInfo my_device_info = {
* .name = TYPE_MY_DEVICE,
* .parent = TYPE_DEVICE,
* .instance_size = sizeof(MyDevice),
* };
*
* static void my_device_register_types(void)
* {
* type_register_static(&my_device_info);
* }
*
* type_init(my_device_register_types)
* </programlisting>
* </example>
*
struct Object
{
/*< private >*/
ObjectClass *clazz;
ObjectFree *free;
GHashTable *properties;
uint32_t ref;
Object *parent;
};
其实也是类似上面class的多态形式,通过第一个参数Object* 将数据可以转化成对应的父类实例和子类实例,通过Object又可以找到对应的class,通过object的parent又可以找到该类的父类。
那么如何实现接口继承呢? 这是一种多继承的方式。
这个分析起来还是有些费劲的。
我们先来看看ObjectClass的定义,这是所有Class类型的基础
/**
* ObjectClass:
*
* The base for all classes. The only thing that #ObjectClass contains is an
* integer type handle.
*/
struct ObjectClass
{
/*< private >*/
Type type;
GSList *interfaces;
const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];
ObjectUnparent *unparent;
GHashTable *properties;
};
其中interfaces 则代表该类实现的接口,这里需要注意,接口是无状态的,也就是只有函数没有数据。所以这里不想抽象类,子类不但继承了状态,还可能覆盖了方法,这里接口只不过是强调一种关系,所以接口更重要的是明确这种关系。
我们来举个例子如何实现接口
typedef struct HotplugHandlerClass {
/* <private> */
InterfaceClass parent;
/* <public> */
hotplug_fn pre_plug;
hotplug_fn plug;
hotplug_fn unplug_request;
hotplug_fn unplug;
} HotplugHandlerClass;
/**
* InterfaceClass:
* @parent_class: the base class
*
* The class for all interfaces. Subclasses of this class should only add
* virtual methods.
*/
struct InterfaceClass
{
ObjectClass parent_class;
/*< private >*/
ObjectClass *concrete_class;
};
typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp);
HotplugHandlerClass的类型为一个接口,接口的实现描述了一种关系,parent_class为接口的类型,concrete_class则为实现接口的类型
HotplugHandlerClass为一个接口,下面有四个函数指针。
我们来找一个随便的实现了HotplugHandlerClass 看它如何实现接口
static void pc_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
......
hc->pre_plug = pc_machine_device_pre_plug_cb;
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
hc->unplug = pc_machine_device_unplug_cb;
......
}
这个方法是PCMachineClass类的初始化方法,做了一些省略,这里可以看出,使用 HOTPLUG_HANDLER_CLASS将参数ObjectClass *oc,转化成了HotplugHandlerClass接口,这是我们突破的关键,是怎么将一个ObjectClass转化为一个接口的呢?
答案就在这个宏里面
#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
#define HOTPLUG_HANDLER_CLASS(klass) \
OBJECT_CLASS_CHECK(HotplugHandlerClass, (klass), TYPE_HOTPLUG_HANDLER)
#define OBJECT_CLASS(class) \
((ObjectClass *)(class))
#define OBJECT_CLASS_CHECK(class_type, class, name) \
((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
__FILE__, __LINE__, __func__))
完全展开如下
((class_type *)object_class_dynamic_cast_assert(((*ObjectClasss) oc), ("hotplug-handler"), __FILE__, __LINE__, __func__))
object_class_dynamic_cast_assert的实现如下
ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
const char *typename,
const char *file, int line,
const char *func)
{
ObjectClass *ret;
if (!class || !class->interfaces) {
return class;
}
ret = object_class_dynamic_cast(class, typename);
if (!ret && class) {
fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
file, line, func, class, typename);
abort();
}
return ret;
}
ObjectClass *object_class_dynamic_cast(ObjectClass *class,
const char *typename)
{
ObjectClass *ret = NULL;
TypeImpl *target_type;
TypeImpl *type;
if (!class) {
return NULL;
}
/* A simple fast path that can trigger a lot for leaf classes. */
type = class->type;
if (type->name == typename) {
return class;
}
target_type = type_get_by_name(typename);
if (!target_type) {
/* target class type unknown, so fail the cast */
return NULL;
}
if (type->clazz->interfaces &&
type_is_ancestor(target_type, type_interface)) {
int found = 0;
GSList *i;
for (i = class->interfaces; i; i = i->next) {
ObjectClass *target_class = i->data;
if (type_is_ancestor(target_class->type, target_type)) {
ret = target_class;
found++;
}
}
/* The match was ambiguous, don't allow a cast */
if (found > 1) {
ret = NULL;
}
} else if (type_is_ancestor(type, target_type)) {
ret = class;
}
return ret;
}
主要实现就在object_class_dynamic_cast中了,主要就是type_is_ancestor这个函数了,对于typename对应的类型为非接口的情况,就是判断target_type是否为type的父类
对于target_type类型为接口的情况下,遍历class所实现的接口,如果实现的接口是typename对应接口的子类,则可以直接转化返回接口。
到这里我们可以推测,如果一个类实现了接口,则会在自己的 class->interfaces里面添加该接口的一个子类实现。
这些代码的实现就在type_initialize中
static void type_initialize(TypeImpl *ti)
{
TypeImpl *parent;
if (ti->clazz) {
return;
}
ti->class_size = type_class_get_size(ti);
ti->instance_size = type_object_get_size(ti);
/* Any type with zero instance_size is implicitly abstract.
* This means interface types are all abstract.
*/
if (ti->instance_size == 0) {
ti->abstract = true;
}
ti->clazz = g_malloc0(ti->class_size);
parent = type_get_parent(ti);
if (parent) {
type_initialize(parent);
GSList *e;
int i;
g_assert_cmpint(parent->class_size, <=, ti->class_size);
memcpy(ti->clazz, parent->clazz, parent->class_size);
ti->clazz->interfaces = NULL;
ti->clazz->properties = g_hash_table_new_full(
g_str_hash, g_str_equal, g_free, object_property_free);
for (e = parent->clazz->interfaces; e; e = e->next) {
InterfaceClass *iface = e->data;
ObjectClass *klass = OBJECT_CLASS(iface);
type_initialize_interface(ti, iface->interface_type, klass->type);
}
for (i = 0; i < ti->num_interfaces; i++) {
TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
for (e = ti->clazz->interfaces; e; e = e->next) {
TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
if (type_is_ancestor(target_type, t)) {
break;
}
}
if (e) {
continue;
}
type_initialize_interface(ti, t, t);
}
} else {
ti->clazz->properties = g_hash_table_new_full(
g_str_hash, g_str_equal, g_free, object_property_free);
}
ti->clazz->type = ti;
while (parent) {
if (parent->class_base_init) {
parent->class_base_init(ti->clazz, ti->class_data);
}
parent = type_get_parent(parent);
}
if (ti->class_init) {
ti->class_init(ti->clazz, ti->class_data);
}
}
static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
TypeImpl *parent_type)
{
InterfaceClass *new_iface;
TypeInfo info = { };
TypeImpl *iface_impl;
info.parent = parent_type->name;
info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
info.abstract = true;
iface_impl = type_new(&info);
iface_impl->parent_type = parent_type;
type_initialize(iface_impl);
g_free((char *)info.name);
new_iface = (InterfaceClass *)iface_impl->clazz;
new_iface->concrete_class = ti->clazz;
new_iface->interface_type = interface_type;
ti->clazz->interfaces = g_slist_append(ti->clazz->interfaces,
iface_impl->clazz);
}
这里可以看出,子类会继承父类的所有接口,另外子类的接口会重新创建interface,他的concrete_class指向interface,他的parent_type指向父类对该接口创建的class
举个例子
struct MyHandler {
InterfaceClass parent;
void (*setA) ()
}
struct MyDevice {
ObjectClass parent;
}
struct MyDeviceChild{
MyDevice parent;
}
类似这样,MyDevice实现了 MyHandler