My first post so please go easy on me!
I know that there\'s no real difference between structs and classes in C++, but a lot of people including me use a struct or class
Generally, I use class
whenever I need to use access specifiers. This has the effect that most of my top-level stuff remain as classes, while the rare POD collections and my not-so-rare inner-class pimpls are usually structs.
Class vs. struct
Using class or struct keyword is a matter of taste together with the 'feeling' it produces on the reader. Technically they are equivalent, but readability is better if structs are used for PODs and C-struct types and classes for anything else.
Basic things that should go in a C++ struct: constructor that initializes the data (I dislike using memset, and it can later bite back if the POD evolves into something different) or construction from other types but not copy constructor.
If you need to define a copy constructor or assignment operator because the compiler generated is not good enough, make it a class.
It is common to use structs also for functors that will be passed to STL algorithms and template metaprogramming, as in
struct square_int {
int operator()( int value )
{
return value*value;
}
};
std::transform( v.begin(), v.end(), v.begin(), square_int() );
or
// off the top of my head
template <typename T>
struct is_pointer { enum { value = false } };
template <typename T>
struct is_pointer<T*> { enum { value = true } };
Member methods vs. free functions
Besides what I have said before, that do not add to what others already answered, I wanted to put some focus on other types of functions that you comment in your post, as comparison operators and the like.
Operators that are meant to be symmetric (comparison, arithmetic), insertion and deletion operators and transformations are usually better implemented as free functions regardless of whether you declare it as a class or struct.
Symmetric operators (with regard to data types) are not symmetric if they are implemented as member functions. The lookup rules won't cast the left hand side to call a member function, but it will apply the same cast to match a free function.
// Example of symmetry with free functions where method would be asymmetric
int main()
{
std::string( "Hello " ) + "world"; // compiles as free / member function
"Hello " + std::string( "world" ); // compiles with free function, fails with member function definition of +
}
In the code above, if operator+ were a member method of std::string the compiler would fail to compile as it cannot cast the const char* literal into a std::string to use the member method.
Insertion and extraction from streams must always be implemented as free functions as the stream is always the left hand side of the operation.
Keeping transformations as free functions decouple the two different types. If A and A' can be converted into one another and you decide to implement transformations as members of A, then A must know A' and all uses of A will depend on A' whether you use it or not. If you define the transformation as a free function, A is complete without A' and the coupling between the two classes/structs will be smaller. The same goes for transformations to/from network, serialization and deserialization. When you implement them inside the class/struct you are forcing all users to know about those transforms.
You could look at what the Standard Library does. Everyone's favourite struct std::pair only has constructors.
I find the use of constructors with structs so convenient and natural that I can't imagine doing without them. I never give structs any other methods, but of course there may be free functions or members of other classes that take them as parameters.
I'll add a very few methods to a struct, as a matter of convenience, only if I'm actually using them. Of course all of them are public. If I need any more than this, it immediately gets converted to a class.
If there's accesser methods for the data members then it's a class.
If you have direct access to the data and can modify it at will, it's a struct.
There's no reason a struct shouldn't have constructors, comparison operators, etc.
Another common use of structs is for template stuff and local RAII or functor classes. These are one-off bits of code that are closer to functions than they are to whole classes, and requiring the extra public:
declaration is just silly. If you look at boost, you'll see a lot of stuff like this:
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
It's clearly not a POD (in fact it doesn't hold any data at all). In other cases you can have RAII class that consist of only a constructor/desctructor:
struct LogOnLeavingScope : public NonCopyable
{
string Message;
LogOnLeavingScope(const string &message) : Message(message) {}
~LogOnLeavingScope() { Log(Message); }
];
Functor classes would offer the same argument:
struct Logger
{
void operator()(const string &message) { Log(message); }
}
I'd say there's no one feature of C++ that implies you should use a class instead of a struct (except maybe virtual functions). It's all about what interface you want to present - use a struct if you are ok with everything being public. If you find you are wanting to add private:
sections, that a good sign you really want a class instead of a struct.