/All/
|
index
catalog
recent
update
post
|
/math/
/tech/
/misc/
/free/
/meta/
/test/
|
Guide
light
mod
Log
P12616
Is this a thing?
Tue 2022-09-27 04:07:15
link
reply
e8625fbe0dc981c897b953403a3d251f36dddb76a12b81883483eeff43387b6c.jpg
388 KiB 925x653
Let A be a class, B be a base class, and suppose C inherits from B. Let X be a class containing an instance of A and B, and Y a class containing an instance of A and C. Then X is a base class of Y.
#include <stdio.h>
typedef struct {
int a_data;
} A;
typedef struct {
int b_data;
} B;
typedef struct {
B super;
int c_data;
} C;
typedef struct {
A a;
B b;
} X;
typedef struct {
A a;
C c;
} Y;
int main() {
Y y = {.a = {.a_data = 0}, .c = {.super = {.b_data = 1}, .c_data = 2}};
X* x = (X*)&y; // It just werks.
printf("x->a.a_data=%d, x->b.b_data=%d\n", x->a.a_data, x->b.b_data);
return 0;
}
Referenced by:
P12622
P12635
P12621
Tue 2022-09-27 04:36:57
link
reply
You could make a polymorphic type Z. Then define X to be Z with the type parameter set to B, and define Y to be Z with the type parameter set to C.
P12622
Tue 2022-09-27 04:38:29
link
reply
3dedee648b523e43fa6e5c6b9bca4442c22edaab94ce675b6e6c0922d3fad84f.png
455 KiB 1691x1225
P12616
it was a bit confusing how you started talking about classes and then showed structs, but i can understand what is happening
in memory, Y has the length of 3 integers: a_data+b_data+c_data
while X has the length of 2 integers: a_data+b_data
so when you make the X pointer point to a Y and dereference it, you are truncating that Y to only a_data+b_data, which is X, so yea it just werks
but if you invert the order of super and c_data, it no longer werks
try to recompile with
typedef struct {
int c_data;
B super;
} C;
then the X pointer will be accessing c_data as if it is b_data
it still kinda works bc they are both integers, even though you are getting c_data instead now, but if they had different types you'd get mangled data
try again with
typedef struct {
float c_data;
B super;
} C;
Referenced by:
P12627
P12627
Tue 2022-09-27 05:16:34
link
reply
P12622
Yeah, the changing type being at the end is important.
I managed to break it with alignment issues.
#include <stdio.h>
#include <stdint.h>
typedef struct {
int8_t a_data;
} A;
typedef struct {
int8_t b_data;
} B;
typedef struct {
B super;
int32_t c_data;
} C;
typedef struct {
A a;
B b;
} X;
typedef struct {
A a;
C c;
} Y;
int main() {
Y y = {.a = {.a_data = 0}, .c = {.super = {.b_data = 1}, .c_data = 2}};
X* x = (X*)&y; // It did not work.
printf("x->a.a_data=%d, x->b.b_data=%d\n", x->a.a_data, x->b.b_data);
return 0;
}
Output (on my machine):
x->a.a_data=0, x->b.b_data=0
Obviously this is all undefined behavior, but I suspect it works as long as the size of the A type is nice and round for alignment.
Referenced by:
P12741
P12635
Tue 2022-09-27 07:20:07
link
reply
P12616
It works in C because there's no real type system.
If you made the B and C pointers in X and Y, and wrapped X and Y in a union, would it not be undefined behavior?
How does this work in object-oriented languages? Should Y actually be a subclass of X?
Referenced by:
P12642
P12704
P12704
Wed 2022-09-28 00:17:35
link
reply
P12635
This is how I would do it in C++, but it incurs the overhead of virtual functions when the unsafe C version doesn't have them. I make virtual getter functions to get pointers to the members, and if the member is not contained, NULL is returned, so the caller should check the pointer before use.
#include <stdio.h>
#include <stdint.h>
class A {
public:
A(int8_t a_data_) : a_data(a_data_) {}
int8_t a_data;
};
class B {
public:
B(int8_t b_data_) : b_data(b_data_) {}
int8_t b_data;
};
class C : public B {
public:
C(int8_t b_data_, int32_t c_data_) : B(b_data_), c_data(c_data_) {}
int32_t c_data;
};
class I_ABC_Container {
public:
virtual A* getA() = 0;
virtual B* getB() = 0;
virtual C* getC() = 0;
};
class X : public I_ABC_Container {
public:
X(A a_, B b_) : a(a_), b(b_) {}
A a;
B b;
virtual A* getA() {
return &a;
}
virtual B* getB() {
return &b;
}
virtual C* getC() {
return NULL;
}
};
class Y : public I_ABC_Container {
public:
Y(A a_, C c_) : a(a_), c(c_) {}
A a;
C c;
virtual A* getA() {
return &a;
}
virtual B* getB() {
return &c;
}
virtual C* getC() {
return &c;
}
};
int main() {
Y y = Y(A(0), C(1, 2));
I_ABC_Container* container = &y; // It just werks.
printf("container->getA()->a_data=%d, container->getB()->b_data=%d\n",
container->getA()->a_data, container->getB()->b_data);
return 0;
}
Referenced by:
P12716
Mod Controls:
x
Reason: