Linked Questions

Popular Questions

I have my custom little OOP-esque inheritance functionality, something like this:

// base class
struct BaseTag;

typedef struct {
    int (*DoAwesomeStuff)(struct BaseTag* pInstance);
} S_BaseVtable;

typedef struct BaseTag{
    S_BaseVtable* pVtable;
    int AwesomeValue;
} S_Base;

// child class
struct ChildTag;

typedef struct {
    S_BaseVtable Base;
    void (*SomeOtherStuff)(struct ChildTag* pInstance);
} S_ChildVTable;

typedef struct ChildTag {
    S_Base BaseClass;
    int EvenAwesomerValue;
} S_Child;

Now let's say I have a Child class constructor where the Base class vtable is overridden with the child vtable:

void Child_ctor(S_Child* pInstance) {
    Base_ctor((S_Base*) pInstance);
    pInstance.BaseClass.pVtable = (S_BaseVtable*) &MyChildVTable;
}

Also in this child vtable, I want to override the DoAwesomeStuff() method from base class with a method like this:

int Child_DoAwesomeStuff(struct BaseTag* pInstance) {
    S_Child* pChild = (S_Child*) pInstance; // undefined behaviour
    return pChild->EvenAwesomerValue;
}

I have seen this pattern in variations occasionally, but I see some problems with it. My main questions are

  • How can I access the S_ChildVtable from a child instance that is hidden behind a S_BaseVtable pointer?
  • How can I properly cast the pInstance argument of Child_DoAwesomeStuff() to an S_Child* type?

As far as I understand the C standard, casting from S_Child* to S_Base* (and the corresponding vtable types) is okay as the first member of S_Child is an S_Base instance. But vice versa it is undefined behaviour.

Would something like S_Child* pChild = (S_Child*)((char*) pInstance) be legal and defined?


Edit

My question was a bit unclear and misleading. It's not the cast itself that I think is UB, but dereferencing pChild after it was cast from pInstance.

I browsed through the C11 standard again to find some reference but not it's not so clear to me anymore.

6.3.2.3/7:

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned (68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

So I guess my question really is - What mechanics need to be in place so that it is ensured that S_Base and S_Child are correctly aligned?

Related Questions