tags:

views:

343

answers:

6

I've just been browsing and spotted the following...

http://stackoverflow.com/questions/54585/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.

+6  A: 

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.

dan04
+1 for actually giving a correct definition of POD. `struct` vs `class` really doesn't matter at all anymore.
D.Shawley
All of the data members of a POD class type must also be POD, so I think limiting the use of `struct` to PODs is too strict. It _might_ be reasonable to limit the use of `struct` to aggregate types, but even then I think the rule would be too struct.
James McNellis
Good point, James. I've never heard anyone object to a `struct` containing `std::string` objects.
dan04
@James: "too struct"? :P (+1 to comment)
Billy ONeal
@Billy: Ha! Well, yes, actually. _To struct or not to struct:_ that is the question. ;-)
James McNellis
@James - good point. A struct containing an std::string member is non-POD. I only think "not a struct" if assignment is overridden at the top level (not just for some members type), but this still breaks my own claimed memcpy rule.
Steve314
+13  A: 

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.

Billy ONeal
Exactly what I use them for too. :)
GMan
I've been pondering functors since this answer. I always use class for these - I never noticed that the standard ones are struct. I have some functors with state. I don't really think of it as state. More like a closure - it affects the `operator()` result, but `operator()` calls don't change that state. I also found http://www.sgi.com/tech/stl/functors.html, with a functor `struct adder` that accumulates, updating state on each `operator()` call. I'm not sure what point I'm making here, though - maybe none. It's interesting, though.
Steve314
@Steve: If operator() doesn't change the state, you should be okay. The main reason you have to be careful about state in STL functors is that STL algorithms are allowed to copy your functor -- by value -- at a whim. This is probably best explained in [Effective STL](http://www.amazon.com/Effective-STL-Specific-Standard-Template/dp/0201749629) Item #39: Make predicates pure functions.
Billy ONeal
@Billy - that sounds OK. My functors-with-state normally only set that state in the constructor.
Steve314
Accepted - hard to say which is the best answer, but the functors point is a good one, and votes == peer pressure
Steve314
A: 

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.

Daniel Paull
Convention is about what the reader understands, not what the compiler understands, and there's plenty of ways to write bad code that compiles without errors or warnings - random indentation, for instance. To me, that "egad!" isn't misplaced. Having a struct to avoid typing "public:" at the top of an interface class seems wrong to me. But then a convention only informs readers (and breaking it only confuses readers) if the convention really exists.
Steve314
You seem assume that I use "struct" for interfaces merely to avoid typing "public:" - interesting, but not right. I have no justification for doing this. It's the way it has always been done in the teams I've worked with. I was taught to do it that way and will continue in that vein until I am forced to do it differently. It is pure convention. Having said that, I do not find it confusing to read code that uses "class" to define (pure) abstract classes.
Daniel Paull
+1  A: 

I use a struct whenever I need an aggregate of public 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.

sbi
+2  A: 

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.

Dennis Zickefoose
+2  A: 

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.

jalf
I'm always a little suspicious of the traditional OOP principles. I can accept a functor as an abstraction or not, irrespective of the real-world argument. Mathematical abstractions often aren't real-world objects. On the other hand, the idea that "the nail hammers itself in" doesn't seem to fit the real world - I see real-world objects called "hammers" (and other tools) and IMO a tool as a separate object (or function) often works well. My rule with abstractions is basically that I know one when I see one.
Steve314
yup, I agree. I didn't want to get into a deep discussion of OOP, but I tend to feel the same way, so perhaps calling *any* of my classes "OOP objects" is a bit misleading. But some classes model some kind of entity in the application (a database, a spaceship, a 3d renderer), and there's usually some abstraction going on in their implementation. Their public interface isn't the same as their internal implementations. I *usually* make those `class`es, to indicate that they encapsulate some the idea of some type of "object" or entity.
jalf