5 ms·
tl;dr: > Simula created inheritance instead of using composition because it allowed their garbage collector to be simpler. In C++, inheritance (and other OO l
by TeeMassive 6y ago
tl;dr:
> Simula created inheritance instead of using composition because it allowed their garbage collector to be simpler.
In C++, inheritance (and other OO languages I assume) is implemented as a composition and when multiple inheritance of the same class happens then the members of the twice parent is inherited twice unless the virtual keyword is used. ( in other words, if B : A, A, C then sizeof B = A + A + C + B's stuff, or if B : virtual A, virtual A, C then sizeof B = A + C + B's stuff). This is why declaring on the stack Parent parent = Child() "works" by just truncating the content of the child that was appended at the end of Parent.
Personally I like to use private inheritance as a composition shortcut since for all intent and purpose it's achieves the same goal with less boilerplate. Outside of that I do use it if it strictly follows the substitution principle with other the members of the base class being used just as much as the child's. Which happens very rarely but does happen. It's like an Allen's key, you probably won't need it except when you must disassembled your IKEA furniture when moving out.
- unkulunkulu 6y agoDoesn’t Parent parent = Child() work because Parent’s constructor is run by implicitly casting ref-to-Child to ref-to-Parent?
- fauigerzigerk 6y agoI don't think that's enough, because Child() still results in an object that is sizeof(Child). In order to store that object in a variable that is sizeof(Parent) it has to be rejigged somehow. I think what TeeMassive is saying is that this rejigging is a simple truncation because the memory layout of (non virtual) inheritance in C++ is a concatenation of Parent and Child objects. I'm not sure whether this is implementation specific though.
- unkulunkulu 5y agoThat’s certainly enough, if you can call a constructor, you don’t have to think about how it works and that the classes are related. The part about “rejigging” and simple truncation happens before the constructor call when you cast ref-to-Child to ref-to-Parent.
- fauigerzigerk 5y agoThere is no casting of references at all in Parent parent = Child().
- unkulunkulu 5y agoSorry for being afk and replying once in a while :/ Parent probably has a copy constructor Parent(const Parent& p) Parent p = Child(); calls it by implicitly casting Child& to const Parent&. That’s what happens. I see that you must have meant this casting step, so indeed the constructor has no control over the rejigging.
- fauigerzigerk 5y agoI see what you mean, but let's go back to the orginal issue and why I think this implicit cast is insufficient as as definition of what happens here. Say you have the obvious minimal implementations of struct Point ... struct Point3D : public Point ... And then you do this: Point p3 = Point3D(1.1, 2.2, 3.3); Point p = p3; On a 64 bit machine this results in sizeof(p) == 16 and sizeof(p3) == 24. So, at some point someone has to decide how to transform p3's 24 byte representation into p's 16 byte representation. In C++, this happens simply by truncting p3, i.e copying the leading 16 bytes of p3 into p and throwing away the trailing 8 bytes (I'm not sure whether or not this is part of the standard). This is not the only imaginable way in which this could possibly happen though, which is why I'm saying that the whole process is not sufficiently defined by stating that a reference to child is cast to a reference to parent.