Unions as Base Class - c++

The standard defines that Unions cannot be used as Base class, but is there any specific reasoning for this? As far as I understand Unions can have constructors, destructors, also member variables, and methods to operate on those varibales. In short a Union can encapsulate a datatype and state which might be accessed through member functions. Thus it in most common terms qualifies for being a class and if it can act as a class then why is it restricted from acting as a base class?
Edit: Though the answers try to explain the reasoning I still do not understand how Union as a Derived class is worst than when Union as just a class. So in hope of getting more concrete answer and reasoning I will push this one for a bounty. No offence to the already posted answers, Thanks for those!

Tony Park gave an answer which is pretty close to the truth. The C++ committee basically didn't think it was worth the effort to make unions a strong part of C++, similarly to the treatment of arrays as legacy stuff we had to inherit from C but didn't really want.
Unions have problems: if we allow non-POD types in unions, how do they get constructed? It can certainly be done, but not necessarily safely, and any consideration would require committee resources. And the final result would be less than satisfactory, because what is really required in a sane language is discriminated unions, and bare C unions could never be elevated to discriminated unions in way compatible with C (that I can imagine, anyhow).
To elaborate on the technical issues: since you can wrap a POD-component only union in a struct without losing anything, there's no advantage allowing unions as bases. With POD-only union components, there's no problem with explicit constructors simply assigning one of the components, nor with using a bitblit (memcpy) for compiler generated copy constructor (or assignment).
Such unions, however, aren't useful enough to bother with except to retain them so existing C code can be considered valid C++. These POD-only unions are broken in C++ because they fail to retain a vital invariant they possess in C: any data type can be used as a component type.
To make unions useful, we must allow constructable types as members. This is significant because it is not acceptable to merely assign a component in a constructor body, either of the union itself, or any enclosing struct: you cannot, for example, assign a string to an uninitialised string component.
It follows one must invent some rules for initialising union component with mem-initialisers, for example:
union X { string a; string b; X(string q) : a(q) {} };
But now the question is: what is the rule? Normally the rule is you must initialise every member and base of a class, if you do not do so explicitly, the default constructor is used for the remainder, and if one type which is not explicitly initialised does not have a default constructor, it's an error [Exception: copy constructors, the default is the member copy constructor].
Clearly this rule can't work for unions: the rule has to be instead: if the union has at least one non-POD member, you must explicitly initialise exactly one member in a constructor. In this case, no default constructor, copy constructor, assignment operator, or destructor will be generated and if any of these members are actually used, they must be explicitly supplied.
So now the question becomes: how would you write, say, a copy constructor? It is, of course quite possible to do and get right if you design your union the way, say, X-Windows event unions are designed: with the discriminant tag in each component, but you will have to use placement operator new to do it, and you will have to break the rule I wrote above which appeared at first glance to be correct!
What about default constructor? If you don't have one of those, you can't declare an uninitialised variable.
There are other cases where you can determine the component externally and use placement new to manage a union externally, but that isn't a copy constructor. The fact is, if you have N components you'd need N constructors, and C++ has a broken idea that constructors use the class name, which leaves you rather short of names and forces you to use phantom types to allow overloading to choose the right constructor .. and you can't do that for the copy constructor since its signature is fixed.
Ok, so are there alternatives? Probably, yes, but they're not so easy to dream up, and harder to convince over 100 people that it's worthwhile to think about in a three day meeting crammed with other issues.
It is a pity the committee did not implement the rule above: unions are mandatory for aligning arbitrary data and external management of the components is not really that hard to do manually, and trivial and completely safe when the code is generated by a suitable algorithm, in other words, the rule is mandatory if you want to use C++ as a compiler target language and still generate readable, portable code. Such unions with constructable members have many uses but the most important one is to represent the stack frame of a function containing nested blocks: each block has local data in a struct, and each struct is a union component, there is no need for any constructors or such, the compiler will just use placement new. The union provides alignment and size, and cast free component access.
[And there is no other conforming way to get the right alignment!]
Therefore the answer to your question is: you're asking the wrong question. There's no advantage to POD-only unions being bases, and they certainly can't be derived classes because then they wouldn't be PODs. To make them useful, some time is required to understand why one should follow the principle used everywhere else in C++: missing bits aren't an error unless you try to use them.

Union is a type that can be used as any one of its members depending on which member has been set - only that member can be later read.
When you derive from a type the derived type inherits the base type - the derived type can be used wherever the base type could be. If you could derive from a union the derived class could be used (not implicitly, but explicitly through naming the member) wherever any of the union members could be used, but among those members only one member could be legally accessed. The problem is the data on which member has been set is not stored in the union.
To avoid this subtle yet dangerous contradiction that in fact subverts a type system deriving from a union is not allowed.

Bjarne Stroustrup said 'there seems little reason for it' in The Annotated C++ Reference Manual.

The title asks why unions can't be a base class, but the question appears to be about unions as a derived class. So, which is it?
There's no technical reason why unions can't be a base class; it's just not allowed. A reasonable interpretation would be to think of the union as a struct whose members happen to potentially overlap in memory, and consider the derived class as a class that inherits from this (rather odd) struct. If you need that functionality, you can usually persuade most compilers to accept an anonymous union as a member of a struct. Here's an example, that's suitable for use as a base class. (And there's an anonymous struct in the union for good measure.)
struct V3 {
union {
struct {
float x,y,z;
};
float f[3];
};
};
The rationale for unions as a derived class is probably simpler: the result wouldn't be a union. Unions would have to be the union of all their members, and all of their bases. That's fair enough, and might open up some interesting template possibilities, but you'd have a number of limitations (all bases and members would have to be POD -- and would you be able to inherit twice, because a derived type is inherently non-POD?), this type of inheritance would be different from the other type the language sports (OK, not that this has stopped C++ before) and it's sort of redundant anyway -- the existing union functionality would do just as well.
Stroustrup says this in the D&E book:
As with void *, programmers should know that unions ... are inherently dangerous, should be avoided wherever possible, and should be handled with special care when actually needed.
(The elision doesn't change the meaning.)
So I imagine the decision is arbitrary, and he just saw no reason to change the union functionality (it works fine as-is with the C subset of C++), and so didn't design any integration with the new C++ features. And when the wind changed, it got stuck that way.

I think you got the answer yourself in your comments on EJP's answer.
I think unions are only included in C++ at all in order to be backwards compatible with C. I guess unions seemed like a good idea in 1970, on systems with tiny memory spaces. By the time C++ came along I imagine unions were already looking less useful.
Given that unions are pretty dangerous anyway, and not terribly useful, the vast new opportunities for creating bugs that inheriting from unions would create probably just didn't seem like a good idea :-)

Here's my guess for C++ 03.
As per $9.5/1, In C++ 03, Unions can not have virtual functions. The whole point of a meaningful derivation is to be able to override behaviors in the derived class. If a union cannot have virtual functions, that means that there is no point in deriving from a union.
Hence the rule.

You can inherit the data layout of a union using the anonymous union feature from C++11.
#include <cstddef>
template <size_t N,typename T>
struct VecData {
union {
struct {
float x;
float y;
float z;
};
float a[N];
};
};
template <size_t N, typename T>
class Vec : public VecData<N,T> {
//methods..
};
In general its almost always better not work with unions directly but enclose them within a struct or class. Then you can base your inheritance off the struct outer layer and use unions within if you need to.

Related

Rationale for non-virtual derived class not being pointer-interconvertible with its first base

There are a few questions and answers on the site already concerning pointer-interconvertibility of structs and their first member variable, as well as structs and their first public base. This question is one of them, for example.
However, what I'm interested in is not the fact that it's undefined behavior to reinterpret_cast (or static_cast through a void *) between a non-standard-layout struct and its public base, but rather the reasoning why the C++ standard currently forbids such casts. The existing questions and answers don't cover this aspect.
Consider the following example in particular (Godbolt):
#include <type_traits>
struct Base {
int m_base_var = 1;
};
struct Derived: public Base {
int m_derived_var = 2;
};
Derived g_derived;
constexpr Derived *g_pDerived = &g_derived;
constexpr Base *g_pBase = &g_derived;
constexpr void *g_pvDerived = &g_derived;
//These assertions all hold
static_assert(!std::is_pointer_interconvertible_base_of_v<Base, Derived>);
static_assert((void *)g_pDerived == (void *)g_pBase);
static_assert((void *)g_pDerived == g_pvDerived);
static_assert((void *)g_pBase == g_pvDerived);
//This is well-defined and returns &g_derived
Derived * getDerived() {
return static_cast<Derived *>(g_pvDerived);
}
//This is also well-defined; outer static_cast added to illustrate the sequence of conversions
Base * getBase() {
return static_cast<Base *>(static_cast<Derived *>(g_pvDerived));
}
//This is UB due to the first static_assert!
Base * getBaseUB() {
return static_cast<Base *>(g_pvDerived);
}
As you can see from the Godbolt link, all three functions compile to the exact same assembly on x86-64 GCC. However, the standard forbids the third variant since Base is not a pointer-interconvertible base of Derived.
My question is: Is there an obvious reason why the standard forbids this kind of cast? In particular, on all implementations that I know of, the value of a pointer to the Base subobject is the same as that of the pointer to the whole Derived, and I don't see a particular reason why Derived should not be considered standard-layout anymore. (In other words, Base lives at offset zero within Derived.) Would it be legal for a C++ implementation to place Base at a non-zero offset within Derived? (Is there maybe an implementation already that does this?)
Note that this question is only about cases without virtual member functions / virtual inheritance / multiple inheritance.
This is really two question:
What is standard layout, like really?
Why is pointer-interconvertibility linked to standard layout?
Standard layout was constructed out of one half of the pre-C++11 concept of "plain old data" types. The other half is trivial copyability (ie: memcpying an instance of the object is just as good as a copy constructor). These two halves didn't really interact, but POD required both.
From a purely standard C++ perspective, standard layout is a requirement for the ability to construct a type whose layout matches an existing type, such that if you shove both of those types into a union, you can access subobjects of the non-active members. This is the core functionality that standard layout enabled within the language since it was invented in C++11.
This is why standard layout only allows one member in the class hierarchy to have non-static data members. If only one class has NSDMs, then there's no question about the ordering between NSDMs of different base classes and so forth. And being able to know a priori what that ordering is is vital for being able to know that two types match.
This is also useful for communicating across languages.
Once standard layout was defined however, it started getting used for things that were... less clearly part of its domain.
For example, standard layout became the determinator for whether offsetof was valid behavior. This is due to offsetof oroginally being based on being a POD type, so when the layout part was spun off, offsetof was updated to use that. However, this was suboptimal, as the only layout-based thing that would break offsetof is having virtual base classes (the offset of members of a virtual base class depends on the most-derived class, which depends on the runtime type of the object). Now, the new restriction was still was better than POD, but it could have been expanded to include more stuff. But that would mean coming up with a new definition.
Something similar likely goes with pointer-interconvertibility. This concept was invented in C++17 to resolve various issues with the object model. There is no evidence in the papers explaining why they picked standard layout to hang pointer-interconvertibility on. But it was an existing tool with well-defined rules that already had well-defined rules on what the "first subobject" was for any given type.
Expanding the rules like you wants requires creating a new definition for "first suboject".
Is a base class pointer-interconvertible to a particular derived class? Well, that depends on what other classes that derived class inherits from. Is the first NSDM pointer-interconvertible to the class it is a member of? That depends on what other classes are involved in the inheritance diagram.
These dependencies already exist, but they all key off of a specific, pre-existing rule. What you want requires creating a new rule that's more complex. It will have to copy 90% of the existing standard-layout rules (forbidding virtual, public/private members, etc) and then add its own rules. The first NSDM is pointer-interconvertible unless any base classes are non-empty. Any particular base class is pointer-interconvertible only so long as all previous base classes in declaration order are empty of NSDMs.
It's so much easier to just piggyback off of the standard layout rules and say "a standard-layout type is pointer-interconvertible with its first NSDM and all of its base classes."
Having an extra rule also imposes some burden on the specification. It's a partial redundancy, and that breeds errors. For example, C++23 is on track to expand standard layout types by removing the forbidding of mixing public and private members, forcing layout to be ordered strictly by declaration. If pointer-interconvertibility had its own rules, it would have been possible to update standard-layout but not pointer-interconvertibility.
Both C and C++ were defined by tradition before standards were written. When the first standards were written, it was more important to avoid requiring that any implementations break programs that existed for them, than to forbid implementations that would processing various programs from changing in such a fashion as to break them.
Although it would be typical for a derived class object to store all of the parent data in a sequence of consecutive bytes, followed by the remainder of the data for the object, it could sometimes be useful for implementations to deviate from that. If a base class had a char field, a derived class had an int, and sub-derived class had another five char fields, an implementation that nestles one of the sub-derived class fields between the base-class field and first-derived class might be able to store data more compactly than one which places everything from each layer in a single sequence of consecutive bytes.
Note that the C++ Standard expressly waives jurisdiction over what C++ programs should be viewed as "conforming". As such, there was no perceived need to ensure that it didn't classify as UB any programs which most implementations should process usefully. If the authors had foreseen the way compilers would treat the Committee's decisions to waive jurisdiction over various constructs as an invitation to process them nonsensically, they probably would have defined behavior in many more corner cases than they actually did.

Casting big POD into small POD - guaranteed to work?

Suppose I've a POD struct which has more than 40 members. These members are not built-in types, rather most of them are POD structs, which in turn has lots of members, most of which are POD struct again. This pattern goes up to many levels - POD has POD has POD and so on - up to even 10 or so levels.
I cannot post the actual code, so here is one very simple example of this pattern:
//POD struct
struct Big
{
A a[2]; //POD has POD
B b; //POD has POD
double dar[6];
int m;
bool is;
double d;
char c[10];
};
And A and B are defined as:
struct A
{
int i;
int j;
int k;
};
struct B
{
A a; //POD has POD
double x;
double y;
double z;
char *s;
};
It's really very simplified version of the actual code which was written (in C) almost 20 years back by Citrix Systems when they came up with ICA protocol. Over the years, the code has been changed a lot. Now we've the source code, but we cannot know which code is being used in the current version of ICA, and which has been discarded, as the discarded part is also present in the source code.
That is the background of the problem. The problem is: now we've the source code, and we're building a system on the top of ICA protocol, for which at some point we need to know the values of few members of the big struct. Few members, not all. Fortunately, those members appear in the beginning of the struct, so can we write a struct which is part of the big struct, as:
//Part of struct B
//Whatever members it has, they are in the same order as they appear in Big.
struct partBig
{
A a[2];
B b;
double dar[6];
//rest is ignored
};
Now suppose, we know pointer to Big struct (that we know by deciphering the protocol and data streams), then can we write this:
Big *pBig = GetBig();
partBig *part = (partBig*)pBig; //Is this safe?
/*here can we pretend that part is actually Big, so as to access
first few members safely (using part pointer), namely those
which are defined in partBig?*/
I don't want to define the entire Big struct in our code, as it has too many POD members and if I define the struct entirely, I've to first define hundreds of other structs. I don't want to that, as even if I do, I doubt if I can do that correctly, as I don't know all the structs correctly (as to which version is being used today, and which is discarded).
I've done the casting already, and it seems to work for last one year, I didn't see any problem with that. But now I thought why not start a topic and ask everyone. Maybe, I'll have a better solution, or at least, will make some important notes.
Relevant references from the language specification will be appreciated. :-)
Here is a demo of such casting: http://ideone.com/c7SWr
The language specification has some features that are similar to what you are trying to do: the 6.5.2.3/5 states that if you have several structs that share common initial sequence of members, you are allowed to inspect these common members through any of the structs in the union, regardless of which one is currently active. So, from this guarantee one can easily derive that structs with common initial sequence of members should have identical memory layout for these common members.
However, the language does not seem to explicitly allow doing what you are doing, i.e. reinterpreting one struct object as another unrelated struct object through a pointer cast. (The language allows you to access the first member of a struct object through a pointer cast, but not what you do in your code). So, from that perspective, what you are doing might be a strict-aliasing violation (see 6.5/7). I'm not sure about this though, since it is not immediately clear to me whether the intent of 6.5/7 was to outlaw this kind of access.
However, in any case, I don't think that compilers that use strict-aliasing rules for optimization do it at aggregate type level. Most likely they only do it at fundamental type level, meaning that your code should work fine in practice.
Yes, assuming your small structure is laid out with the same packing/padding rules as the big one, you'll be fine. The memory layout order of fields in a structure is well-defined by the language specifications.
The only way to get BigPart from Big is using reinterpret_cast (or C style, as in your question), and the standard does not specify what happens in that case. However, it should work as expected. It would probably fail only for some super exotic platforms.
The relevant type-aliasing rule is 3.10/10: "If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined: ...".
The list contains two cases that are relevant to us:
a type similar (as defined in 4.4) to the dynamic type of the object
an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union)
The first case isn't sufficient: it merely covers cv-qualifications. The second case allows at the union hack that AndreyT mentions (the common initial sequence), but not anything else.

In C++, why struct is in fact class?

The other topic and responses there made me ask this question:
Why does C++ allow struct to behave just like class? At one hand, C++ made it compatible with C-struct by making it's members public by default (just like in C), while on the other hand, it made it look-like class by allowing it to be inherited from classes, and applying other object-oriented techniques (not so much like C-struct anymore). Why did it not make it just plain old C-struct with no OOP? Any special reason?
It allows existing structs to be fitted in with C++ code in a more natural way. For instance, you can add member functions to a struct and inherit from a struct, which wouldn't be possible if structs and classes inhabited different universes.
Stroustrup's original intent was to avoid a fracturing of the community between the traditional C-style "struct" camp, and the OO "class" crowd. He also cited the benefits of having just one concept instead of two.
From a language point of view, structures and unions are just types of class. It makes the language specification simpler if there are fewer concepts (with a small letter 'c') and it also makes specifying the language less error prone as it is less easy to miss something 'obvious' out if every common property had to spelled out for each of structures, unions and non-structure, non-union classes.
C++ classes have a lot of potential functionality over C structures but as C structures can be viewed as a degenerate C++ class, it is simplest to allow them to be exactly this. There is no benefit to having a special structure concept as well as a class concept.
From ISO/IEC 14882:2003, 9 [class] / 4:
A structure is a class defined with the class-key struct; its members and base classes are public by default. A union is a class defined with the class-key union; its members are public by default and it holds only one data member at a time.
"public" default for struct fields is required for compatibility with C
code which may access struct fields.
"public" default for struct inheritance is required so that the child class
could be used in place of base struct.
It could be possible to make struct into a different data type than classes
(ie disallow access type specifiers and methods in it), but that would be both
inconvenient for programming and add a lot of unnecessary work for compiler
developers.
In C there were only structs to begin with. Object orientation began when libraries were designed when pointers to those structures were passed to a set of library functions that were dependent on that structure. One good example is the Win32 API. It isn't a C++ interface, it's a C interface; but it's still object oriented.
Classes are almost the same as structures memory-wise. The member functions are not stored as part of the class member data. It's simply a structure with extra function pointers on the end. So a class' function table is dereferenced in the same way that Windows API uses object orientation, but it encapsulates it so you don't see it.
Inheritance, polymorphism; who cares? People were fine with C, and still doing fine with C.
Allowing something you declare as struct to really be a class allows type-safety when creating a C interface.
You can forwardly declare your struct for your C interface:
struct Foo;
You can declare methods on it
void doStuffThatModifiesFoo( struct Foo * foo, ... );
struct Bar getStuffFromFoo( const struct Foo * foo );
You can also write create and destroy methods for it.
Underneath you implement Foo not as a C struct but as a class but your C clients do not need to know that. This is better than passing it around as a void * then casting (not safe if someone passes you a void* to a completely different type and you cast it).
The "compatibility with C" issue is only meant in one direction: Old, valid C-code should also compile as C++ code. The other way round is impossible as soon as any language feature that only C++ has is being used.
That means in C++, you always write classes, you can omit using the keyword struct at all ; though some, including me, think they come in handy to show that a class just a simple collection of named values, with no real encapsulation or possibly complex behaviour.

Why union can't be used in Inheritance?

I saw below thing in c++ standard (ยง9.5/1):
A union shall not have base classes. A union shall not
be used as a base class.
A union can have member functions
(including constructors and
destructors), but not virtual (10.3)
functions
From above, union can have constructor and destructor as well.
So why is it not allowed in Inheritance ?
EDIT: For answering comments:
If union is allowed as a base class, its data can be used by a derived class. If derived class is interested to use only one member of union, this way can be used for saving memory. I think, this is improper inheritance. Is it better to have union inside derived class in that case ?
If union is allowed as derived class, it can use services of base class. For example, if Union has multiple types of data. As we know, only one type of data can be used. For each type of data, a base class is present to offer services for that particular type. In this case, multiple inheritance can be used to get services of all base classes for all types of data in Union. This also i feel as improper usage of inheritance. But is there any equivalent concept to achieve content in this point?
Just my thoughts...
Here is a simple workaround:
struct InheritedUnion
{
union {
type1 member1;
type2 member2;
};
};
struct InheritsUnion : InheritedUnion
{};
By making the union anonymous, it works just as if the base type were actually a union.
(This answer was written for C++03, the situation may have changed since C++11)
I can't imagine any compelling reason for excluding it... more that there's no particularly good reason for including it. Unions just aren't used enough to matter that much, and there are heavy restrictions on the type of members in the union, restrictions that prevent OO practices. Those restrictions - and the burden of manually tracking the particular variable(s) in a union that have validity - mean pretty much the first thing you want to do with a union is encapsulate it in a class, then you can inherit from that anyway. Letting the union be part of the inheritance chain just spreads the pain around.
So, anything that might give casual C++ users the impression that unions could be mixed into their OO-centric code would cause more trouble than good. Unions are basically a hack for memory conservation, fast-but-nasty data reinterpretation and implementing variants, and tend to be an implementation detail rather than an interface one.
You've added a bit to your question with your edit... thoughts follow.
If union is allowed as a base class, its data can be used by a derived class. If derived class is interested to use only one member of union, this way can be used for saving memory. I think, this is improper inheritance. Is it better to have union inside derived class in that case ?
So, we're discussing:
union U { int i; double d; };
struct D : U { };
U's data members would either have to be - implicitly or explicitly - public, protected or private. If they're public or protected, then they're not encapsulated, and we're back in the "share the pain" scenario mentioned above. U has less ability to encapsulate them than a class containing a union. If they're private, then they could just as easily be a union data member in a class.
If union is allowed as derived class, it can use services of base class. For example, if Union has multiple types of data. As we know, only one type of data can be used. For each type of data, a base class is present to offer services for that particular type. In this case, multiple inheritance can be used to get services of all base classes for all types of data in Union. This also i feel as improper usage of inheritance. But is there any equivalent concept to achieve content in this point?
Ok, this is where things get weird. So, we've got:
union U : public A, private B { };
Firstly, let me be a bit more explicit about something. Unions can't contain complex, encapsulated objects - they're the antithesis of encapsulation. You're pretty much limited to POD data, and can't have non-default constructors etc.. Note I'm talking about the data members of the union, and not the union itself. So, A and B would - if those union-content rules remain - be very limited, and the ability of U to derive not particularly useful.
That leads into the question of why unions can't manage more complex objects in some safe way. Well, how could they do it? Obvious answer is add a hidden enum to say which one is valid, and some rules about which type should be constructed by default, invoking the destructor first when a different enum field is assigned to, etc etc etc.... Maybe they should throw if someone does something to the member that's not currently constructed? Sounds ok?
Well, firstly, the overhead of an enum might not be necessary, as client code might use one member then another in a known-appopriate order. Checks and exceptions in the language itself are a similar overhead... they may be able to be factored down to a single check before multiple uses if left to the client code. In both cases, you'd be paying for some management overhead that only some applications need - a very un-C++ approach.
Ignoring that, unions aren't that simple anyway. Like enums, their use is designed to be flexible and would be hard to communicate to the compiler so it could clean up, check and automate it. You might think "huh? enums are complex?", but each enum is - conceptually generalised - effectively an arbitrary set of independent bitfields of varying width. It's non-trivial to describe which ones are meant to be mutually exclusive or dependent etc.. The compiler doesn't buy into the problem space at all. Similarly, a union may have one or more concurrently legitimate views on the same data, while others are invalid, with subtleties to boot. For example: a union of int64_t, double, and char[4] could always be read as an int64_t or char[4] after being set as a double, but the other way around might read an invalid double and cause undefined behaviour, unless you're re-reading values that came from a double at some earlier time, perhaps in a serialisation/deserialisation library. The compiler doesn't want to buy into the management of that, which is what it would have to do to ensure object members of unions obeyed the promises implicit in their own encapsulation.
You ask "is it better to have union inside derived class?"... no - doesn't generally work as most objects can't be put into a union (see above). You hit this problem whether the union is inside the derived class, or - through the new language features you postulate - the union actually is the derived class.
I do understand your frustration though. In practice, people do sometimes want unions of arbitrary non-trivial objects, so they hack it up the hard and dirty way using reinterpret cast or similar, managing memory alignment of some space big enough for the set of objects they'll support (or - easier but slower - a pointer to them). You'll find this sort of thing in the boost variant and any libraries. But, you can't derive from them... the knowledge about appropriate usage, the extent of safety checks etc. just isn't deducible or expressible in C++. The compiler's not about to do that for you.

Is it always evil to have a struct with methods?

I've just been browsing and spotted the following...
When should you use a class vs a struct in C++?
The consensus there is that, by convention, you should only use struct for POD, no methods, etc.
I've always felt that some types were naturally structs rather than classes, yet could still have a few helper functions as members. The struct should still be POD by most of the usual rules - in particular it must be safe to copy using memcpy. It must have all member data public. But it still makes sense to me to have helper functions as members. I wouldn't even necessarily object to a private method, though I don't recall ever doing this myself. And although it breaks the normal POD rules, I wouldn't object to a struct having constructors, provided they were just initialise-a-few-fields constructors (overriding assignment or destructors would definitely be against the rules).
To me a struct is intuitively a collection of fields - a data structure node or whatever - whereas a class is an abstraction. The logical place to put the helper functions for your collection-of-fields may well be within the struct.
I even think I once read some advice along these lines, though I don't remember where.
Is this against accepted best practice?
EDIT - POD (Plain Old Data) is misrepresented by this question. In particular, a struct can be non-POD purely because a member is non-POD - e.g. an aggregate with a member of type std::string. That aggregate must not be copied with memcpy. In case of confusion, see here.
For what it's worth, all the standard STL functors are defined as structs, and their sole purpose is to have member functions; STL functors aren't supposed to have state.
EDIT: Personally, I use struct whenever a class has all public members. It matters little, so long as one is consistent.
As far as the language is concerned, it doesn't matter, except for default private vs. public access. The choice is subjective.
I'd personally say use struct for PODs, but remember that "POD" doesn't mean "no member functions". It means no virtual functions, constructors, destructor, or operator=.
Edit: I also use structs for simple public-access aggregates of data, even if their members aren't PODs.
I tend to use struct a lot.
For the "traditional" OOP classes (the ones that represent a specific "thing"), I tend to use class simply because it's a common convention.
But most of my classes aren't really OOP objects. They tend to be functors, and traits classes and all sorts of other more abstract code concepts, things I use to express myself, rather than modelling specific "things". And those I usually make struct. It saves me having to type the initial public:, and so it makes the class definition shorter and easier to get an overview of.
I also lean towards making larger, more complex classes class. Except this rarely affects anything, because I lean even more towards refactoring large, complex classes... And then I'm left with small simple ones, which might be made struct's.
But in either case, I'd never consider it "evil". "Evil" is when you do something that actively obfuscates your code, or when you make something far more complex than necessary.
But every C++ programmer knows that struct and class mean virtually the same thing. You're not going to be confused for long because you see a struct Animal {...}; You know that it's a class designed to model an animal. So no, it's not "evil" no matter which way you do it.
When I have control over the style guides, everything is defined as a struct. Historically, I wanted all my objects to be one or the other, since I was taught it was undefined behavior to forward declared a struct as a class, and vice versa (I'm not sure if this was ever actually true, its just what I was told). And really, struct has the more reasonable default state.
I still do the same because I've never been convinced of the value of using it as a form of documentation. If you need to convey that an object only has public members, or doesn't have any member functions, or whatever arbitrary line you chose to draw between the two, you have actual documentation available for that. Since you never actually use the struct or class keyword when using the type, you would need to go hunting for the definition anyhow if you want the information. And with everybody having their own opinion on what struct actually means, its usefulness as self-documentation is reduced. So I shoot for consistency: everything as one or the other. In this case, struct.
Its not a popular way of doing things, to say the least. Fortunately for everybody involved, I very rarely have control over the coding standards.
I use a struct whenever I need an aggregate of public data members (as opposed to class, which I use for types that come with a certain level of abstractions and have their data private).
Whether or not such a data aggregate has member functions doesn't matter to me. In fact, I rarely ever write a struct without also providing at least one constructor for it.
You said, "To me a struct is intuitively a collection of fields - a data structure node or whatever". What you are describing is Plain Old Data. The C++ standard does have an opinion of what POD means with respect to C++ language features. I suggest that, where possible, you adopt the meaning of POD used in C++0x.
I need to find a reference for this, but I thought that, as far as type definitions are concerned, the keywords "struct" and "class" are to be synonyms in C++0x. The only difference being that class defaults to private members, while a struct defaults to public. This means that you'll never see complier error messages like "Type X first seen using struct, now seen using class." once we're all using C++0x.
I think that it is wrong to have strict rules on when to use class and when to use struct. If consistency is important to you, the go ahead and make a coding standard that has what ever sort of rules you like. Just make sure everyone knows that your coding standard relates to how you want you code to look - it doesn't relate to the underlying language features at all.
Maybe to give an example where I break all your rules, you say "To me a struct is intuitively a collection of fields - a data structure node or whatever - whereas a class is an abstraction." When I want to write a class that implements some abstraction, I define the interface as a struct with pure virtual methods (egad!) - this is exposed in a header, as too is a factory method to construct my concrete class. The concrete class is not exposed i a public header at all. Since the concrete class is a secret, it can be implemented however I like and it makes no difference to external code.
I'd suggest that if you think that the keywords struct and class have any relation to the concept of POD, then you're not understanding C++ yet.