C中的构造函数和析构函数

时间:2014-05-11 09:34:52

标签: c pointers function-pointers

我正在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函数初始化。

2 个答案:

答案 0 :(得分:1)

  1. p被分配给class->ctor的返回值,该值被声明为void *,因此它是一个无效指针。查看String_ctor的定义,您可以看到这会返回self String *,因此在这种情况下,您可以安全地投放void *String *

  2. 这是通过*(const struct Class **)p = class;实现的。由于classString的第一个成员,因此指向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}的指针}}