> For the complete documentation index, see [llms.txt](https://richardweiyang-2.gitbook.io/understanding_qemu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://richardweiyang-2.gitbook.io/understanding_qemu/00-devices/07-class_obj_interface.md).

# 类型、对象和接口之间的转换

因为用c语言实现了一个类面向对象的设备模型，在类型和实例之间的转换都需要手工实现。所以在代码中有几个重要的宏定义来完成这样的工作。

## obj -> class

对应的obj找到它的class。

```
#define OBJECT_GET_CLASS(class, obj, name) \
    OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
```

obj就是我们传入的对象实例， object\_get\_class就是获得obj->class这个成员，也就是对应的class。 class就是这个对象对应的class的类型，name呢就是这个class的名字。 对于没有intefaces的类型来说，这就是一个强制类型转换。也就是得到了obj对应的类型。

## ObjectClass -> 子Class

在上面的图中我们也看到，类型之间也有着父子关系。比如PCIDeviceClass就是DeviceClass的子类。

所以有时候在代码中我们需要从父类获得具体的子类。这个工作交给了：

```
#define OBJECT_CLASS_CHECK(class_type, class, name) \
    ((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
                                               __FILE__, __LINE__, __func__))
```

这个宏其实就是上面的那个宏，如果没有interfaces成员这也是一个强制类型转换。把class类型转换成class\_type。

但是因为Qemu自身的面向对象的模型，子类和父类的基地址相同所以能够通过强制转换来得到子类。

其实这么看，反过来转换也是可以的。

## Object -> 子Object

同上面的类型一样，object也有父子关系。所以当代码中需要从父对象转换到一个具体的子对象时就要用：

```
#define OBJECT_CHECK(type, obj, name) \
    ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \
                                        __FILE__, __LINE__, __func__))
```

对obj来讲就没有类型Class这么复杂了，在生产环境中纯粹就是强制类型转换，把obj类型转换到type类型。 因为按照Qemu的面向对象模型，父子obj的基地址是一样的。

## Class -> InterfaceClass

这个转换和Class到子Class的方式一样，也是

```
#define OBJECT_CLASS_CHECK(class_type, class, name) \
    ((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
                                               __FILE__, __LINE__, __func__))
```

但是因为这个Class有interfaces成员，所以会在interfaces链表上查找名字为name的接口。

如果有则返回对应name的接口。

## Object -> Interface

从上面的转换可以看出，如果想要从一个obj得到interface可以分成两步：

* obj -> class
* class -> interface

但是因为当Class有interface成员，且传入的name就是接口类型的名字时，obj可以直接转换成接口。

也就是用OBJECT\_CLASS\_CHECK可以直接转换得到。

## obj -> 虚obj

所以虚obj就是obj对象对应的Class类型的接口类型的对象。这么说还真有点绕，估计我自己过段时间来看也得花点时间回忆回忆。

之所以我叫它虚obj，是因为接口类型本身是没有对应的对象的。所以这个东西还挺神奇，没想到代码里还会这么用。

大家也一定觉得不信，那先举个例子：

```
#define MEMORY_DEVICE(obj) \
     INTERFACE_CHECK(MemoryDeviceState, (obj), TYPE_MEMORY_DEVICE)

typedef struct MemoryDeviceState MemoryDeviceState;
```

这个MemoryDeviceState就定义了这么一个类型，没有任何的成员。而它对应的Class类型是TYPE\_MEMORY\_DEVICE的接口类型。

而在代码中通常的用法还是要将这个虚obj再转换到接口类型。通常用法如下：

```
const MemoryDeviceState *md = MEMORY_DEVICE(obj);
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj);
```

这个obj就是一个真实的obj对象，而md则是对应的虚obj。其实他们俩的指是一样的，都指向了同一个地址。

还是觉得很神奇，为什么代码要这么写呢？就不能直接传obj么？

我能想到的一个作用就是在debug选项打开时能够检测类型，而不至于传错参数。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://richardweiyang-2.gitbook.io/understanding_qemu/00-devices/07-class_obj_interface.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
