Why can't structs be derived from?
Jonathan M Davis
jmdavisProg at gmx.com
Tue Mar 15 08:00:54 PDT 2011
On Tuesday 15 March 2011 06:25:13 Jens wrote:
> It seems rather fundamental to be able to compose a new struct from a
> given struct using inheritance. Why is this not allowed?
>
> struct slist_node
> {
> slist_node* next;
> };
>
> template <class T>
> struct slist_node<T>: public slist_node
> {
> T data;
> };
Classes are polymorphic. Structs are not. This is by design. One of the major
reasons for this is slicing. In C++, if you have a pointer to an object, the
pointer can be of a base type or of the same type as what is pointed to. You
don't necessarily care. The correct code is called polymorphically. When you
assign it to another pointer, it works just fine. You can even safely assign it
to a pointer of a base type.
class A {}
class B : public A {}
A* a = new B();
B* b = new B();
You can do the same in D with classes and references (and pointers, except that
pointers aren't polymorphic in D). However, what happens if the type is on the
stack directly?
A a = *(new B());
B b = *(new B());
Your object just got sliced ( http://en.wikipedia.org/wiki/Object_slicing ).
When it's on the stack, the compiler must know _exactly_ what type of object it
is. That means that you can't have it be a different type than what you say it
is. And that means that while assigning a B to a B works just fine, assigning a B
to an A means that all the parts of that object that are B-specific, get lost.
Only the parts that are part of an A get copied (since you just assigned it to
an A). Take
class A
{
int x;
}
class B : public A
{
int y;
float z;
}
An A has an int in it. A B has an additional y and z in it. When you assign a B
to an A, the y and z variables get lost. In many cases, this results in a
completely invalid object and is _rarely_ what you really want. If you're not
careful, this can be a big problem in C++. In C++, you _must_ use pointers if
you want polymorphism. This also means that you generally avoid assigning
dereferenced pointers to stack variables.
D's solution is to make it so that there is a clear separation between non-
polymorphic types on the stack and polymorphic types on the heap. Structs have
no polymorphism and no inheritance. They live on th stack. Classes do have
polymorphism nad ihneritance. They live on the heap. You _can_ have pointers to
structs, but they're still non-polymorphic, and you can't normally stick a class
on the stack.
There are other benefits to making structs non-polymorphic (such as not needing a
virtual table), but the main one is to avoid the slicing issue. Overall, it
works quite well. One of the major, potential sources of bugs in C++ is
completely avoided in D.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list