Vou adicionar às respostas existentes porque o C ++ moderno agora é uma coisa e as Diretrizes Principais oficiais foram criadas para ajudar com questões como essas.
Esta é uma seção relevante das diretrizes:
C.2: Use classe se a classe tiver um invariante; use struct se os membros de dados puderem variar independentemente
Uma invariante é uma condição lógica para os membros de um objeto que um construtor deve estabelecer para que as funções de membro público assumam. Depois que o invariante é estabelecido (normalmente por um construtor), cada função de membro pode ser chamada para o objeto. Um invariante pode ser declarado informalmente (por exemplo, em um comentário) ou mais formalmente usando Expects.
Se todos os membros de dados podem variar independentemente uns dos outros, nenhum invariante é possível.
Se uma classe tiver dados privados, um usuário não pode inicializar completamente um objeto sem o uso de um construtor. Portanto, o definidor de classe fornecerá um construtor e deve especificar seu significado. Isso efetivamente significa que o definidor precisa definir um invariante.
Execução
Procure structs com todos os dados privados e classes com membros públicos.
Os exemplos de código fornecidos:
struct Pair { // the members can vary independently
string name;
int volume;
};
// but
class Date {
public:
// validate that {yy, mm, dd} is a valid date and initialize
Date(int yy, Month mm, char dd);
// ...
private:
int y;
Month m;
char d; // day
};
Classs funcionam bem para membros que são, por exemplo, derivados uns dos outros ou inter-relacionados. Eles também podem ajudar na verificação de sanidade na instanciação.Structs funcionam bem para ter "pacotes de dados", onde nada de especial está realmente acontecendo, mas os membros logicamente fazem sentido serem agrupados.
A partir disso, faz sentido que classexistam para suportar encapsulamento e outros conceitos de codificação relacionados, para os quais structos programas simplesmente não são muito úteis.