C 来自void*的双指针和单指针?

C 来自void*的双指针和单指针?,c,pointers,c11,C,Pointers,C11,我读了一本关于用C实现OOP的书,发现了以下代码: void delete (void * self) { const struct Class ** cp = self; if (self && * cp && (* cp) -> dtor) self = (* cp) -> dtor(self); free(self); } 我想知道为什么作者创建了双指针而不是单指针 像这样 void delete (v

我读了一本关于用C实现OOP的书,发现了以下代码:

void delete (void * self)
{ 
    const struct Class ** cp = self;
    if (self && * cp && (* cp) -> dtor)
        self = (* cp) -> dtor(self);
    free(self);
}
我想知道为什么作者创建了双指针而不是单指针 像这样

void delete (void * self)
{ 
    const struct Class * cp = self;
    if (self && cp && cp -> dtor)
        self = cp -> dtor(self);
    free(self);
}

有什么不同吗?

在作者的对象系统中,每个对象结构的第一个元素都包含一个指向其类的指针:

typedef struct Object1 {
    Class *myclass;
    int data;
} Object1;

typedef struct Object2 {
    Class *myclass;
    double data;
} Object2;
这意味着,通过将指向任何对象的
void*
指针视为
Class**
指针,可以在不知道对象的实际类型的情况下跟踪类指针。这是标准允许的,因为:

6.7.2.1结构和工会规范 15[…]指向 经过适当转换的结构对象指向其初始成员(或者如果该成员是 位字段,然后是它所在的单元),反之亦然。[……]

因此,任何指针
Object1*
Object2*
等都可以转换为指向其第一个元素的指针,即
Class**
(因为其中的第一个元素的类型为
Class*
,指向第一个元素的指针的类型为
Class**
)。有关更多信息,请参阅

这是一种法律方法,但有点难以遵循。一个等价物就是写

typedef struct BaseObject {
    Class *myclass;
} BaseObject;
并要求每个对象结构包含一个
BaseObject
实例作为其第一个成员;
delete
函数然后将
self
强制转换为
BaseObject*
并写入
((BaseObject*)self)->myclass->dtor

void delete (void * self)
{ 
    BaseObject *base = self;
    if (self && base->myclass && base->myclass—>dtor)
        self = base->myclass->dtor(self);
    free(self);
}

由于结构设计:

*(const struct Class **)p=class;
在那里:

如图所示

void * new(const void *_class,...)
{
 const struct Class *class=_class;
 void *p=calloc(1,class->size);
 assert(p);
 *(const struct Class **)p=class;  //<------look here!

 if(class->ctor)
 {
  va_list ap;
  va_start(ap,_class);
  p=class->ctor(p,&ap);
  va_end(ap);
 }
 return p;
}
void*新建(常量void*_类,…)
{
常量结构类*类=_类;
void*p=calloc(1,类->大小);
断言(p);
*(const struct Class**)p=Class;//ctor)
{
va_列表ap;
va_启动(ap,_类);
p=类别->部门(p和ap);
va_端(ap);
}
返回p;
}

在该系统中,每个对象在第一个字段中都包含一个指向其类的指针。实际上,
Class**c=self
从对象实例获取类结构。

因此,您可能必须回到书中作者讨论设计的地方,因为我们不可能知道作者的意图。此外,请检查如何调用此
delete
函数。如果它传递了指针的地址(例如,
&pointer
),那么第二个版本将崩溃并烧掉。@JoachimPileborg是的,它会崩溃,但你也可以传递
指针,而不是
&pointer
。你能详细解释一下这个不可移植的句子吗?它在哪些方面不可移植?操作系统?编译器?对不起,我错了;这是允许的。6.7.2.1:15指向结构对象的指针,经过适当转换后,指向其初始成员(或者如果该成员是一个位域,则指向其所在的单元),反之亦然。我只是想知道我是否多年来每天都在编写不可移植的代码;)-在您最后给出的删除示例中,您使用的不是“base”,而是“self”。这是正确的吗?@ASHISHNEGI很好,修正了。为什么我不能这样做:const struct Class**pt=(const struct Class**)p*pt=clas;是“const struct*”吗?那么为什么C允许它在一行中这样更改?这是一个好的设计吗?我从正确的来源读对了吗?