一,前言
由于看到了类似的写法,都用到了object_dynamic_cast_assert函数,所以分析下。
二,源码分析
- 看到如下代码的写法,很眼熟
CortexMBoardState *board = CORTEXM_BOARD_STATE(machine);
machine 的类型是MachineState *
#define CORTEXM_BOARD_STATE(obj) \
OBJECT_CHECK(CortexMBoardState, (obj), TYPE_CORTEXM_BOARD)
#define OBJECT_CHECK(type, obj, name) \
((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \
__FILE__, __LINE__, __func__))
- 展开后就是
((CortexMBoardState *)object_dynamic_cast_assert(((Object *)((machine))), ("cortexm:" "machine"), __FILE__, __LINE__, __func__))
- 主要分析object_dynamic_cast_assert函数
Object *object_dynamic_cast_assert(Object *obj, const char *typename,
const char *file, int line, const char *func)
{
……
inst = object_dynamic_cast(obj, typename);
……
}
Object *object_dynamic_cast(Object *obj, const char *typename)
{
if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) {
return obj;
}
return NULL;
}
- 所以最主要的是object_class_dynamic_cast函数
ObjectClass *object_class_dynamic_cast(ObjectClass *class,
const char *typename)
{
……
/* 根据name直接找class */
type = class->type;
if (type->name == typename) {
return class;
}
/* 根据name来找到Type */
target_type = type_get_by_name(typename);
if (type->class->interfaces &&
type_is_ancestor(target_type, type_interface)) {
……
}
/* 根据父类的name来找type */
else if (type_is_ancestor(type, target_type)) {
ret = class;
}
}
上面我加的注释其实描述的不对,应为用了找class,其实class是传入的参数,是通过object_get_class(obj)传入的obj->class,而object是应用层machine将类型MachineState*强转为object*的。所以这里不能说找class,只能说check class。所以从宏定义的名字OBJECT_CHECK也看出这个函数的含义是检查用的。
若我不检查,直接CortexMBoardState *board = CortexMBoardState *)machine来赋值也可以,但是添加check就可以检查object或父类的object是否匹配,避免错误。
至于可以强转的原因是machine可以理解为是CortexMBoardState的父类。
typedef MachineState CortexMBoardParentState;
typedef struct {
// private:
CortexMBoardParentState parent_obj; //子类中首个成员包含了父类
// public:
BoardGraphicContext graphic_context;
} CortexMBoardState;
//父类
MachineState *machine
三,小结
这种就类似c++中的基类转为派生类,说不定c++源码的实现也是这样的设计,又学习到一招,这就是我喜欢底层的原因,因为能更加深入的了解设计方法及运行机制。
补充:子类的创建都没malloc,都是从父类object中获取的指针,说明父类object创建的时候就已经malloc好了子类的而内存空间,所以子类的赋值才需要先获取父类的指针。
举例
DeviceClass *dc =DEVICE_GET_CLASS(dev);
接着就直接读取dc->realize的成员内容了。原因是.class_size在申请内存空的时候已经预留了子类DeviceClass的内存空间。
static
const TypeInfo stm32_mcu_type_info = {
.abstract = true,
.name = TYPE_STM32_MCU,
.parent = TYPE_STM32_MCU_PARENT,
.instance_init =
stm32_mcu_instance_init_callback,
.instance_size = sizeof(STM32MCUState),
.class_init =
stm32_mcu_class_init_callback,
.class_size = sizeof(STM32MCUClass)
/**/
};
所以看下class_size是否包括了DeviceClass的结构体size,果然有的。
STM32MCUClass
CortexMClass
SysBusDeviceClass
DeviceClass