Struct versus class?

Started by
45 comments, last by Nish Wk 10 years, 2 months ago

Hi,

Just wondering. What do you see as the 'boundary' when you prefer a class versus a struct?

Was thinking about this when I was adding functions to my VECTOR3 struct, the number of operators has grown, and I'm thinking of also adding (inline) functions for cross- and dot- product. Included are already getting the magnitude and normalizing.

For now I don't see reasons to move from a struct to a class.

Operators work nice and do exactly what I want without to much code (not even sure how to do that within a class.....)

Somehow my mind says, as long as it's a relatively 'simple' object, just use a struct and don't 'waste classes' on it (not sure though how to explain this rationally :))

What are your thoughts?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement

Since in C++ a struct and class are very nearly identical...

When I see a cluster of data with no functions, or perhaps only with a constructor or very minimal functions, where the data is accessed directly, I see this as a struct. Everything is public.

When I see an object that has private internal state, that is manipulated and acted upon rather than used as a container for data, I see a class. Data is private, interfaces are public or protected, you shouldn't touch the innards.

Thanks, that's a nice addition. In my vector struct indeed the members are all accessible (and should be).

Would you add for example a function in the struct to calculate the cross or dot product? Or would you add 'Global functions' (yikes!! smile.png) in the same header/ cpp files

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Free functions, absolutely. A member function should be seen as something that operates on the object is is called on. For example std::string::c_str, where you ask the std::string object for a pointer to its string value, or std::vector::push_back where you ask the std::vector object to append a value you supply as a parameter. But you don't ask one vector for their cross or dot product; they are simply calculations on free inputs.

As frob mentioned, in C++ a class and a struct are pretty much identical. The choice of which to use is yours to make, seeing as the following two are very much the same:


struct Vec
{
   float x, y, z;
};

class Vec
{
public:
   float x, y, z;
};

One issue i ran into when i used a mix of structs and classes was when forward declaring them. Sometimes i would simply forget if Vec was a class or a struct. Similar with Color, Rect, Transform, etc. So i settled on using classes only, and if something needs to have all of it's members public, i simply set them as public and not protected/private.

devstropo.blogspot.com - Random stuff about my gamedev hobby

I'm going to suggest that maybe you should do some more reading on class vs. struct, and on interface design. It sounds to me like you've got an unseasoned understanding of some things. That's not a dig at you, its just something I'm picking up on, and its very common for people to have misunderstandings that lead to here.

Just for example, you say "global functions" like its a bad thing, when in fact such "free functions" should very often be prefered. This is a common misunderstanding that stems from "object-orientitis" where one believes that all interfaces belong literally inside the class, but in reality the portion of an interface that has access to a class's internal state should be as small as possible to maximize encapsulation and maximize cohesion.

throw table_exception("(? ???)? ? ???");

All good advice above. Global functions (aka free functions) are indeed a good thing.
It really shits me (and other OOD aficionados) that Java decided to outlaw them and also push their own modified ideas about OO... But that's another rant ;)

Anyway, in classes with private state, usually there's some kinds of constraints (aka invariants) that have to be enforced by the public functions -- e.g. Resize may check for "size < 0" before changing the private member variables. If there is a bug in the private data, e.g. Size is -1 somehow, then you only have to look at these member functions to find the cause.
If a function *can* be implemented as a free function (i.e. doesn't *have* to be a member function), it's a good choice to do so. In these cases, your free function only accesses the public members of the class -- so, if there's a bug in the private details, you know your free function can't be to blame.
That's one example of why 'decoupling' is good, but it's become a general rule of thumb in software engineering to try and keep things as loosely coupled as possible.

In your struct case, the above example doesn't apply of course, because everything is public!
However, it can still be nice organizationally to keep the data structures themselves separate from the algorithms that operate on those structures.
For example, there's an endless number of operations that could be done on a vector, so it would be nice to be able to add new operations without having to edit the shared vector struct endlessly, or make vector.h over 9000 lines long.
C# has hacked around this issue by adding "extension classes" to their language...

There's many examples of this in std::, just look at the stuff in <algorithm>, such as how searching and sorting are decoupled from std::list and std::vector!

As frob mentioned, in C++ a class and a struct are pretty much identical. The choice of which to use is yours to make, seeing as the following two are very much the same:


struct Vec
{
   float x, y, z;
};

class Vec
{
public:
   float x, y, z;
};

One issue i ran into when i used a mix of structs and classes was when forward declaring them. Sometimes i would simply forget if Vec was a class or a struct. Similar with Color, Rect, Transform, etc. So i settled on using classes only, and if something needs to have all of it's members public, i simply set them as public and not protected/private.

Actually they are not pretty much identical they are identical, the code generated from them is exactly the same, a struct can have all the same things as a class.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Actually they are not pretty much identical they are identical, the code generated from them is exactly the same, a struct can have all the same things as a class.

The only difference is semantical regarding the default access rule for members (public vs private), which is why i said "pretty much identical", but yeah, the generated bytecode is the same.

devstropo.blogspot.com - Random stuff about my gamedev hobby

One thing I like to do with C++ is use structs as classes, but hide the class related code when C is accessing it. This came in handy a few times for me.


struct whatever_t
{
#ifdef __cplusplus
public:
  void func1();
  int  func2(void*);
  byte func3(char, float);

public:
#else
//  struct _vtbl
//  {
    void (*func1)(struct whatever_t* This);
    void (*func2)(struct whatever_t* This, void*);
    void (*func3)(struct whatever_t* This, char, float);
//  }*vtbl;
#endif
  int var1, var2, var3;
};

#ifndef __cplusplus
 void whatever_func1(struct whatever_t* This);
 void whatever_func2(struct whatever_t* This, void*);
 void whatever_func3(struct whatever_t* This, char, float);
#endif

I once needed the functionality of classes, but at the same time, needed compatibility with C and C++. This is how I did it.

EDIT: Minus the vtable.

This topic is closed to new replies.

Advertisement