mil*_*bos 2 c oop class double-pointer
我正在阅读 C 中的 OOP,并且有这个标题:
#ifndef _NEW_H
#define _NEW_H
#include <stdarg.h>
#include <stddef.h>
#include <assert.h>
void *new (const void *type, ...);
void delete (void *item);
typedef struct
{
size_t size;
void *(*ctor)(void *self, va_list *app);
void *(*dtor)(void *self);
void *(*clone)(const void *self);
int (*differ)(const void *self, const void *x);
} class_t;
inline void *new (const void *_class, ...)
{
const class_t *class = _class;
void *p = calloc(1, class->size);
assert(p);
*(const class_t **)p = class; //why would you cast to double pointer, when you immediately dereference it?
if (class->ctor)
{
va_list args;
va_start(args, _class);
p = class->ctor(p, &args);
va_end(args);
}
return p;
}
#endif //_NEW_H
Run Code Online (Sandbox Code Playgroud)
现在我不明白这个表达:
*(const class_t **)p = class;
Run Code Online (Sandbox Code Playgroud)
类型是什么意思const class_t **?它就像一个数组的数组?但如果我想要自定义类(即不仅是指向 struct 的指针class_t,而是更多“公共”方法),则整个类不是类型数组class_t。那么为什么我要将 void 指针转换为双指针并立即取消引用它呢?我该如何理解呢?
关于该声明的书:
* (const struct Class **) p = class;
p 指向对象的新内存区域的开头。我们强制对 p 进行转换,将对象的开头视为指向 struct class_t 的指针,并将参数 class 设置为该指针的值。
对 的调用calloc()用于分配未指定“类”类型的 1 个元素的数组,其中该类型的第一个成员预计是一个指针class_t*(因此class->size必须至少为sizeof(class_t*),但可以更高)。 calloc()可能会被使用,而不是仅仅malloc()这样,由 表示的任何其他数据成员都class->size将被零初始化,否则memset()将需要显式的。
奇怪的强制转换+取消引用只是为了让代码可以将输入class指针直接存储到该class_t*分配对象的第一个成员中。
可以使用双指针访问数组。取消引用这样的指针可以得到数组中第一个元素的地址。在本例中,该地址也恰好与该成员的地址相同class_t*。
用 OOP 术语来说,内存中对象的布局通常以指向对象类的 vtable 的指针开始,其中包含指向该类的“虚拟”方法的函数指针列表。当一个类“派生”时,后代通过简单地将对象的 vtable 指针设置为新的函数指针列表来“覆盖”虚拟方法。OOP 的概念在 C 中并不真正存在,但它是 C++ 的基础。在 C 中,它必须手动实现,这就是这段代码所做的。
基本上,代码正在为已分配的对象分配此内存布局:
------------ --------------------
无效 *p -> | 类_t* | -> | 尺寸_t 尺寸 |
------------ --------------------
| ... | | 无效(*ctor)()|
------------ --------------------
| 无效 (*dtor)() |
--------------------
| 无效(*克隆)()|
--------------------
| 无效(*不同)()|
--------------------
完成相同分配的另一种方法是对“类”类型使用 typedef 以便于访问,例如原始代码等效于:
------------ --------------------
void *p -> | class_t* | -> | size_t size |
------------ --------------------
| ... | | void (*ctor)() |
------------ --------------------
| void (*dtor)() |
--------------------
| void (*clone)() |
--------------------
| void (*differ)() |
--------------------
根本不使用任何 typedef 或强制转换,memcpy()可以用来完成同样的事情,例如:
typedef struct
{
class_t *vtable;
// other data members, if class->size > sizeof(class_t*) ...
} class_info_t;
inline void *new (const void *_class, ...)
{
const class_t *class = _class;
class_info_t *p = (class_info_t*) calloc(1, class->size);
assert(p);
p->vtable = class;
// other data members are implicitly zeroed by calloc() ...
...
}
Run Code Online (Sandbox Code Playgroud)