First of all, a struct
is completely equivalent to a class
, but with the default member access being public
rather than private
.
Now, in Object Oriented Programming (OOP), it's not considered good practice to have public
data members (variables), because that makes all your code dependent on the internals of the class
, and thus breaking a primordial principle of OOP, and that is...
Holy and Sacred Encapsulation
Encapsulation is the coding philosophy that states that a class should englobe both data and the code that manages it in a single tight entity. That is, you don't access data directy, but rather you use methods from the class
to manipulate such data. This has several design advantages, such as that you'll know that no code except the one inside the class may incorporate bugs with respect to the manipulation of such information.
Now, get()
ers and set()
ers, otherwise known as accessors, are a complete lie! With accessors, you're tricking yourself into thinking that you're respecting encapsulation, when you're rather breaking it! It adds bloat, unnecessary verbosity, bugs, and everything but encapsulation. Instead of having a class Person
with unsigned getAge()
and void setAge(unsigned)
, have it with a unsigned getAge()
and a void incrementAge()
or however you want to call it.
Now, to your question's core...
"Plain old" structs
Encapsulation is not always desired. Although you should (usually) not do this on header files (again, for at least some bit of encapsulation), you may create static plain old struct
s that are private to a single translation unit. My recommendation is to make them even "older" than they already are, i.e...
- All data members are
public
.
- No methods.
- No constructors (except implicit ones).
- Inheritance is always public, and only allowed from other plain old
struct
s.
- I repeat, don't put them on header files!
Now, another use for plain old struct
s is (ironically) metaprogrammatic exporting of constexpr
data and types, otherwise known as modern-hardcore-template-metaprogramming-without-having-to-type-public
-everywhere, for example...
template<bool B, typename T>
struct EnableIf {};
template<typename T>
struct EnableIf<true, T> {
typedef T type;
};
template<bool B, typename T>
using SFINAE = typename EnableIf<B, T>::Type;