Is it always evil to have a struct with methods?

21,471

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
21,471

Related videos on Youtube

Admin
Author by

Admin

Updated on March 23, 2020

Comments

  • Admin
    Admin about 4 years

    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.

    • James McNellis
      James McNellis almost 14 years
      IMO, this is entirely subjective and everyone will have his own opinion. I, for example, will use struct for any class that has only a small number of members, all of which are public (e.g., a derived exception class). One of my coworkers complains loudly any time a struct has member functions.
  • michelson
    michelson almost 14 years
    +1 for actually giving a correct definition of POD. struct vs class really doesn't matter at all anymore.
  • James McNellis
    James McNellis almost 14 years
    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.
  • dan04
    dan04 almost 14 years
    Good point, James. I've never heard anyone object to a struct containing std::string objects.
  • Admin
    Admin almost 14 years
    @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.
  • Admin
    Admin almost 14 years
    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.
  • GManNickG
    GManNickG almost 14 years
    Exactly what I use them for too. :)
  • Admin
    Admin almost 14 years
    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 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.
  • Billy ONeal
    Billy ONeal almost 14 years
    @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 Item #39: Make predicates pure functions.
  • Admin
    Admin almost 14 years
    that sounds OK. My functors-with-state normally only set that state in the constructor.
  • Daniel Paull
    Daniel Paull almost 14 years
    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.
  • Admin
    Admin almost 14 years
    Accepted - hard to say which is the best answer, but the functors point is a good one, and votes == peer pressure
  • Admin
    Admin almost 14 years
    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.
  • josesuero
    josesuero almost 14 years
    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 classes, to indicate that they encapsulate some the idea of some type of "object" or entity.