我正在A.T. Schreiner
读一本书OOC,我在这段代码中停留在以下一行:
struct Class {
size_t size;
void *(* ctor) (void *self, va_list *app);
};
struct String {
const void *class; // must be first
char *text;
};
void *new(const void *_class, ...) {
const struct Class *class = _class; // assign the address of `struct String` class
void *p = calloc(1, class->size); // allocate the sizeof(struct String);
assert(p);
*(const struct Class **)p = class; // Force the conversion of p and set the argument `class` as the value of this pointer.
if(class->ctor) {
va_list ap;
va_start(ap, _class);
p = class->ctor(p, &ap); // Now what is `p` here, a `struct String` or `struct Class`.
// and if it is `struct Class` then how it convert to `struct String` in `String_ctor` function
// given below.
va_end(ap);
}
return p;
}
static void *String_ctor(void *_self, va_list *app) {
struct String *self = _self;
const char *text = va_arg(*app, const char *);
self->text = malloc(strlen(text) + 1);
assert(self->text);
strcpy(self->text, text);
return self;
}
// Initialization
static const struct Class _String = {
sizeof(struct String),
String_ctor
};
const void *String = &_String;
// Call like this:
int main(void) {
void *a = new(String, "some text");
}
现在,正如您所看到的,在new
函数中,以下行p = class->ctor(p, &ap)
让我很困惑。您可以看到上述评论。
另外,我想知道const void *class
函数struct String
的{{1}}如何由new
函数初始化。
答案 0 :(得分:1)
p
被分配给class->ctor
的返回值,该值被声明为void *
,因此它是一个无效指针。查看String_ctor
的定义,您可以看到这会返回self
String *
,因此在这种情况下,您可以安全地投放void *
到String *
这是通过*(const struct Class **)p = class;
实现的。由于class
是String
的第一个成员,因此指向String
的指针将具有与指向其class
字段的指针相同的地址。因此,当您将p
转换为Class **
并写入时,您就会写入class
字段。
答案 1 :(得分:0)
p
既不是struct String
也不是struct Class
。它是一个指针。它指向一块内存。如何解释这种记忆是一个有趣的问题。
假设我们传递一个实现字符串的struct Class
对象的地址,第一个calloc
调用会分配一个大小为struct String
的内存块。因此,假设p
是指向struct String
的指针,这是完全合理的。
new
函数对struct String
或任何其他"类"知之甚少。几乎没有什么,除了任何这样的struct
的第一个元素是指向struct Class
对象的指针的事实。由于指向任何struct
的指针与指向其第一个元素的指针(模数类型)相同,这使得p
也指向指向的指针{{1} }。所以这一行:
struct Class
为*(const struct Class **)p = class;
指向的指向结构的类分配适当的值。
现在这一行
p
调用构造函数,传递" self"在任何OO环境中指向它的指针。它还将构造函数的结果再次分配给p = class->ctor(p, &ap);
,大概是因为ctor可以(但不必)重新分配对象。
回顾一下:p
是一个指向p
的指针,struct String
将其解释为指向new
的第一个元素的指针,该元素必须是指向{{1}的指针}}