5

Or does it?

Should an object-oriented design use a language construct that exposes member data by default, if there is an equally useful construct that properly hides data members?

EDIT: One of the responders mentioned that if there's no invariant one can use a struct. That's an interesting observation: a struct is a data structure, i.e. it contains related data. If the data members in a struct are related isn't there's always an invariant?

andreas buykx
  • 12,608
  • 10
  • 62
  • 76

17 Answers17

20

In C++, structs and classes are identical except for the default public/privateness of their members. (This default is easily, and usually, overridden.)

However, most programmers think of a struct as a "data object" and a class as an "interactive object". That's not a bad thing; and in fact should be taken advantage of. If something is just an inanimate lump of data (even maybe if it has a couple of inspector methods), use a struct for it; it'll save a bit of effort when a programmer is trying to see what it's for.

Artelius
  • 48,337
  • 13
  • 89
  • 105
14

Don't be a hiding zealot. If your get/set methods do nothing but simply copy verbatim the value onto/from a hidden, private field, you've gained nothing over a public member and only complicate unnecessarily your class (and, depending on the intelligence of the compiler, slow its usage a bit).

There's a case for not allowing direct access when your setter methods do some validation, copy the data somewhere else, process it a bit before storing it, etc. Same in the case of getters that actually calculate the value they return from multiple internal sources, and hide the way it's derived (I believe Bertrand Meyer speaks a bit about this in his book)

Or if allowing the users of your class to directly change such a value would have unintended side effects or breaks an assumption some of your member classes have about the values. On those situations, by all means, do hide your values.

For instance, for a simple "Point" class, that only holds a couple coordinates and colour, and methods to "Plot" it and "Hide" it on screen, I would see no point in not allowing the user to directly set the values for its fields.

Joe Pineda
  • 5,521
  • 3
  • 31
  • 40
  • 2
    "you've gained nothing over a public member". You have gained link compatibility if the method isn't defined in the header, and you ever want to change the implementation beyond trivial access. Of course there's a fairly strong YAGNI there, but if you're writing a lib for binary distribution, – Steve Jessop Oct 31 '08 at 15:06
  • ... you might want to avoid clients needing a recompile when you make a supposedly API-compatible change. – Steve Jessop Oct 31 '08 at 15:07
4

In C# for example I use structs for some simple better-left-as-values data types:

public struct Point
{
    int X;
    int Y;
}

and for any P/Invoke to libraries where the arguments are structs you'll have to use them for certain.

Do they belong in the general design of an application? Of course they do, use a struct when it makes sense to do so. Just like you'd use a enum with bit flags when it makes sense to do so instead of resorting to some complicated string parsing for storing combined values.

cfeduke
  • 23,100
  • 10
  • 61
  • 65
4

In C++, the difference between a struct and a class is the default visibility of its contents (i.e. public for a struct, and private for a class). I guess this difference was to keep C compatibility.

But semantically, I guess this is subject to interpretation.

An example of struct

In a struct, everything is public (by default), meaning the user can modify each data value as desired, and still the struct remains a valid object. Example of struct:

struct CPoint
{
   int x ;
   int y ;

   CPoint() : x(0), y(0) {}

   int getDistanceFromOrigin() const
   {
      return std::sqrt(x * x + y * y) ;
   }
} ;

inline CPoint operator + (const CPoint & lhs, const CPoint & rhs)
{
   CPoint r(lhs) ;
   r.x += rhs.x ;
   r.y += rhs.y ;
   return r ;
}

You can change the x value of a CPoint, and it still remains a valid CPoint.

Note that, unlike some believe, a C++ struct can (and should) have constructors, methods and non-member functions attached to its interface, as shown above.

An example of class

In a class, everything is private (by default), meaning the user can modify the data only through a well defined interface, because the class must keep its internals valid. Example of class:

class CString
{
   public :
      CString(const char * p) { /* etc. */ } ;
      CString(const CString & p) { /* etc. */ } ;

      const char *     getString() const { return this->m_pString ; }
      size_t           getSize() const { return this->m_iSize ; }

      void             copy { /* code for string copy */ }
      void             concat { /* code for string concatenation */ }

   private :
      size_t           m_iSize ;
      char *           m_pString ;
} ;

inline CString operator + (const CString & lhs, const CString & rhs)
{
   CString r(lhs) ;
   r.concat(rhs) ;
   return r ;
}

You see that when you call concat, both the pointer could need reallocation (to increase its size), and the size of the string must be updated automatically. You can't let the user modify the string by hand, and forget updating the size.

So, the class must protect its internal, and be sure everything will be correctly updated when needed.

Conclusion

For me, the difference between a struct and a class is the dependencies between the aggregated data.

If each and every piece of data is independent from all the others, then perhaps you should consider a struct (i.e., a class with public data member).

If not, or if in doubt, use a class.

Now, of course, in C#, the struct and class are two different type of objects (i.e. value types for structs, and referenced types for classes). But this is out of this topic, I guess.

Community
  • 1
  • 1
paercebal
  • 81,378
  • 38
  • 130
  • 159
2

Technically, a struct is a class with the default visibility of public (a real class has a default visibility of private).

There is more of a distinction in common use.

A struct is normally just a collection of data, to be examined and processed by other code.

A class is normally more of a thing, maintaining some sort of control over its data, and with behavior specified by associated functions.

Typically, classes are more useful, but every so often there's uses for something like a C struct, and it's useful to have a notational difference to show it.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
2

The matter is easy. If the class does have invariants to guarantee, you should never make the members constraining the invariant public.

If your struct is merely an aggregate of different objects, and doesn't have an invariant to hold, you are indeed free and encouraged to put its members public. That's the way std::pair<T, U> in C++ does it.

What's that invariant stuff?

Simple example: Consider you have a Point class whose x and y members must always be >= 0 . You can make an invariant stating

/* x >= 0 && y >= 0 for this classes' objects. */

If you now make those members public, clients could simply change x and y, and your invariant could break easily. If the members, however, are allowed to contain all possible values fitting their own invariants respectively, you could of course just make those members public: You wouldn't add any protection to them anyway.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

A struct is essentially a model class but with different syntax.

public struct Point {
    int x;
    int y;
}

is logically the same as:

public class Point {
    private int x;
    private int y;
    public void setX(int x) { this.x=x; }
    public int getX(); { return x; }
    public void setY(int y) { this.y=y; }
    public int getY(); { return y; }
}

Both are a mutable model that holds pair of integer values called x and y. So I would say that it's a valid object oriented construct.

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
0

Yes. It's like a mini-class.

Seibar
  • 68,705
  • 38
  • 88
  • 99
0

Formally, in C++ a struct is a class with the visibility of its members set to public by default. By tradition structs are used to group collection of homogeneous data that have no particular reasons for being accessed by specific methods. The public visibility of its members makes structs preferred to class to implement policy classes and metafunctions.

Nicola Bonelli
  • 8,101
  • 4
  • 26
  • 35
0

Yes, they do. They have different semantic than classes. A struct is generally considered and treated as a value type, while a class is generally considered and treated as a reference type. The difference is not as much pronunciated in every day programming; however, it is an imprtant difference when it comes to things like marshalling, COM interop and passing instances around.

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
  • That's true for C#, but not for C++. In C++ the semantics are identical except for default visibility. – Ferruccio Nov 07 '08 at 20:59
  • I disagree. The semantic of the struct is value type in C++ as well; C++ just does not provide compile or runtime time enforcement of this semantic. In COM (which is mostly C++ world) struct is a marshaled by value, and classes are marshaled by reference through the implemented COM interfaces. – Franci Penov Nov 09 '08 at 18:27
0

I use structs regularly - mostly for data received from the network or hardware. They are usually wrapped in a class for use by higher level parts of the program.

My rule of thumb is a struct is always pure data, except for a constructor. Anything else is a class.

Steve Fallows
  • 6,274
  • 5
  • 47
  • 67
  • I do the same thing. The only time I make an exception is for small functors. Making those structs makes them a little more visually compact. – Ferruccio Nov 07 '08 at 21:02
0

Most answers seem to be in favor of a struct as something to be acceptable and useful, as long as it does not have a behavior (i.e. methods). That seems fair enough.

However, you can never be sure that your object does not evolve into something that may need behavior, and hence some control over its data members. If you're lucky enough that you have control over all users of your struct, you can go over all uses of all data members. But what if you don't have access to all users?

andreas buykx
  • 12,608
  • 10
  • 62
  • 76
  • I think adding methods to a struct is OK, as long as they're "helpers". If you've designed something to allow public member access, and you don't control client code, then you must support that public member access for ever. It's true whether your thing was a class or a struct. – Steve Jessop Oct 31 '08 at 15:18
  • If you don't have access to all users, then don't use a struct. – skiphoppy Dec 09 '08 at 17:30
0

A struct, as used in C or C++, and the struct used in C# ( or any .Net language ), are such different animals that they probably should not even have the same name... Just about any generalization about structs in one language can easily be false, or true for a completely unrelated reason, in the other.

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
0

If there is a need for invariant, make it a class. Otherwise, struct is OK.

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
0

See these similar questions:

When should you use a class vs a struct in C++?

What are the differences between struct and class in C++

plus:

According to Stroustrup in the C++ Programming Language:

Which style you use depends on circumstances and taste. I usually prefer to use struct for classes that have all data public. I think of such classes as "not quite proper types, just data structures."

Community
  • 1
  • 1
crashmstr
  • 28,043
  • 9
  • 61
  • 79
0

There's nothing wrong with using structs per se, but if you're finding yourself needing them, you should ask what's wrong with your analysis. Consider, eg, the Point class above: it gives some little improvement in readability, since you can always use

Point foo;
//...
foo.x = bar;

in place of, say, having a two element array as in

#define X 0
#define Y 1
//...
foo[X] = bar;

But classes are meant to hide details behind a contract. If your Point is in some normalized space, the values may range in the half-open interval [0.0..1.0); if it's a screen they may range in [0..1023]. If you use a struct in place of accessors, how will you keep someone from assigning foo.x = 1023 when x should be everywhere < 1.0?

The only reason C++ programmers used structs for Points is that back at the dawn of time --- 20 years ago, when C++ was new --- inlining wasn't handled very well, so that foo.setX(1023) actually took more instructions than foo.x = 1023. That's no longer true.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
-1

Structs are fine as long as they're kept small. As you probably know, they are allocated on the stack (not the heap) so you need to watch the size. They can come in handy for small data structures like Point, Size, etc. A class is usually the better choice though, being a reference type and all.

Ty.
  • 2,220
  • 1
  • 15
  • 14
  • In C++ structs are not allocated on the stack per-se. – Jasper Bekkers Oct 30 '08 at 21:54
  • Could you elaborate on the per-se? Or point me to where I can find out? – Feet Oct 30 '08 at 21:55
  • They can be created with malloc(), operator new; they can be global variables. Those won't go on the stack. Structs declared locally might be stack allocated. – Artelius Oct 30 '08 at 22:02
  • In C++ you choose to allocate an object on the stack or the heap, when using new or malloc you allocate something on the heap as Artelius says. @Robert P: the question has been tagged C++ so I guess it's a fair assumption ;-) – Jasper Bekkers Oct 30 '08 at 22:09