My first post so please go easy on me!
I know that there's no real difference between structs and classes in C++, but a lot of people including me use a struct or class to show intent - structs for grouping "plain old data" and classes for encapsulated data that has meaningful operations.
Now, that's fine but at what point do you start to think that something isn't just a struct anymore and should become a class?
Things I think are reasonable for structs to have:
- constructors with simple initialisation code only.
- serialization code such as stream insertion / extraction operators.
Things I'm not so sure about, but would probably do:
- comparison operators
- Simple transformation functions - for example byteswapping all the members after receiving data from an external source.
I don't think structs should have:
- dynamic memory allocation.
- destructor.
- complex member functions.
Where do the boundaries lie???
Also, is it reasonable to have class instances as members of a struct? e.g.
class C {private: int hiddenData; public: void DoSomething();};
struct S {int a; float b; C c; };
S s; s.c.DoSomething();
Remember, I'm not on about what you CAN do with C++, I'm interested in what you SHOULD do when designing good software.
Thoughts?
I think there are three major, coherent schools of thought:
struct
andclass
interchangeably.struct
s only to represent small POD.struct
s as records.I can't make a conclusive argument for either of these strategies. I tend to follow path 2 but I also use structs for non-POD types when I see it fitting, especially for function objects (even if these may not fulfil POD requirements).
(Incidentally, the C++ FAQ lite has a pretty good definition of POD).
EDIT I didn't touch template metaprogramming techniques, such as using
struct
for placeholders (type tags) or to implement metafunctions. I guess there's absolutely no controversy in these cases: since they never contain methods (or even data), always usestruct
).Generally, I use
class
whenever I need to use access specifiers. This has the effect that most of my top-level stuff remain as classes, while the rare POD collections and my not-so-rare inner-class pimpls are usually structs.The only methods I like to put on structs are property-type methods, simple transforms (and, if appropriate for the type, operators), and non-default constructors.
Properties
For instance, I might define a
RECT
struct as below:The "set" methods return the new value to support assignment chaining in the case that the compiler supports properties as an extension.
Simple transforms
For POD types that store complex data, I might include methods that perform simple transformations on that data. An obvious example might be including Rotate, Scale, Shear, and Translate methods on a TransformationMatrix struct.
Operators
Really just an extension of the above, if operators make sense for the type, I will add them to a struct. This can be appropriate and necessary to maintain the atomicity of the object. An obvious example is standard arithmetic operators on a Complex struct.
Constructors
I prefer not to have a default constructor on my structs. I don't want to allocate an array of PODs and suffer the invocation of a thousand (or whatever) default initializations. If
memset
initialization won't suffice, I'll provide an Initialize method.I will, however, provide a non-default constructor on structs. This is especially useful when one or more fields can be inferred from partial construction.
I use struct whenever I want to use data member as interface of the object. I'd change the struct to a class, whenever there is a need to add a private section.
If there's accesser methods for the data members then it's a class.
If you have direct access to the data and can modify it at will, it's a struct.
There's no reason a struct shouldn't have constructors, comparison operators, etc.
I'll add a very few methods to a struct, as a matter of convenience, only if I'm actually using them. Of course all of them are public. If I need any more than this, it immediately gets converted to a class.