Menu

Structs em C++: agrupe dados relacionados em um único tipo

Structs em C++ explicadas: como reunir variáveis relacionadas em um único tipo, declarar e inicializar objetos struct, dar funções membro e construtores a uma struct, e qual é a real diferença entre struct e class.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Por que agrupar dados

Até agora cada variável ficava por conta própria: um int aqui, uma string ali. Mas programas reais lidam com coisas compostas de várias partes: um ponto tem um x e um y, um estudante tem um nome, uma idade e um GPA. Passar tudo isso como variáveis soltas e separadas é propenso a erros; nada as mantém unidas, e uma função que precisa das três precisa receber os três parâmetros.

Uma struct resolve isso. Ela define um novo tipo que reúne variáveis relacionadas — seus membros — em uma única unidade. Uma vez definida, você trata o conjunto inteiro como um único valor que pode armazenar, copiar e passar para funções.

Você acessa cada membro com o operador ponto (s.name, s.age). O ponto e vírgula após a } de fechamento da definição de uma struct é obrigatório; omiti-lo é um dos erros de compilação mais comuns entre iniciantes em C++.

Inicializando uma struct

Atribuir cada campo manualmente funciona, mas é verboso e é fácil esquecer um membro. A opção mais limpa é a inicialização por agregado: liste os valores entre chaves, na mesma ordem em que os membros foram declarados.

Cuidado com o caso padrão vazio: Point p; (sem chaves) deixa x e y com valores de lixo, porque membros de tipos embutidos não são zerados automaticamente. Point p{}; os inicializa por valor em 0. Prefira as chaves. Você também pode embutir valores padrão diretamente na definição, de modo que até Point p; comece limpo:

Structs como parâmetros de funções

Uma struct é um único valor, então uma função pode receber um parâmetro em vez de três. Apenas lembre que passar uma struct por valor copia todos os membros. Para qualquer coisa maior que alguns ints, passe por referência const para evitar a cópia: a mesma regra que você viu na página de referências.

Retornar uma struct inteira de uma função é a maneira idiomática de devolver vários valores de uma vez, muito mais limpa do que gerenciar várias referências de saída.

Adicionando funções membro e construtores

Uma struct não se limita a dados. Ela pode conter funções membro que operam sobre seus próprios membros, e um construtor que inicializa o objeto no momento em que ele é criado. É aqui que uma struct começa a parecer um pequeno objeto com comportamento.

Dentro de uma função membro, os membros são acessados pelo nome (width, height): eles se referem à cópia deste objeto. Marcar area() const diz ao compilador que a função apenas lê o objeto, o que permite chamá-la também sobre valores const Rectangle. Construtores são um tópico por si só, incluindo aquela sintaxe de lista de inicialização : width(w); a página de construtores aprofunda o assunto.

Struct vs. class: a real diferença

Você talvez já tenha ouvido que "structs são para dados, classes são para objetos". Isso é uma convenção, não uma regra da linguagem. Em C++ uma struct e uma class são quase a mesma coisa: a única diferença embutida é o nível de acesso padrão.

struct S {
    int x;        // public por padrão
};

class C {
    int x;        // private por padrão
};

Os membros de uma struct são public a menos que você os marque de outra forma; os de uma class começam como private. É isso: ambos podem ter construtores, funções membro, herança e tudo mais. Você pode até adicionar especificadores de acesso explícitos a uma struct para ocultar membros:

A conclusão prática: use struct para conjuntos transparentes de dados em que cada campo deve ser acessado livremente (um Point, uma Color, um registro de configuração), e recorra a class quando quiser proteger o estado interno por trás de uma interface pública. O compilador os trata da mesma forma; a palavra-chave apenas sinaliza sua intenção.

Arrays e vectors de structs

Como uma struct é um tipo comum, você pode colocar muitas delas em um array ou em um vector e percorrê-las como qualquer outro valor.

Observe as chaves aninhadas: cada {"Keyboard", 49.99} inicializa por agregado um Product, e as chaves externas constroem o vector. Usar const Product& no laço baseado em intervalo evita copiar cada struct a cada iteração; remova o & e você duplicaria cada elemento desnecessariamente.

Próximo: Enums

Structs permitem construir um tipo a partir de vários valores agrupados. O próximo capítulo segue o caminho oposto: um enum define um tipo que pode conter exatamente um valor de um conjunto pequeno e nomeado, perfeito para coisas como Color::Red, Direction::North ou o status de uma máquina de estados. Você verá como enum class oferece constantes legíveis e com segurança de tipos que combinam naturalmente com as structs e classes que você está construindo agora.

Perguntas frequentes

O que é uma struct em C++?

Uma struct é um tipo definido pelo usuário que agrupa várias variáveis relacionadas (chamadas de membros) sob um único nome. Em vez de gerenciar separadamente as variáveis string name, int age e double gpa, você as reúne em um único tipo Student e passa esse objeto por toda parte. Uma struct também pode ter funções membro e construtores: no C++ moderno ela é uma classe completa cujos membros são public por padrão.

Qual é a diferença entre struct e class em C++?

Tecnicamente, apenas o nível de acesso padrão: os membros de uma struct são public a menos que você diga o contrário, enquanto os de uma class são private por padrão. O mesmo vale para herança. Todo o resto (construtores, funções membro, métodos, herança) funciona de forma idêntica. Por convenção, os programadores usam struct para conjuntos simples de dados e class para tipos com invariantes e detalhes internos ocultos.

Como inicializar uma struct em C++?

A forma mais simples é a inicialização por agregado com chaves na ordem dos membros: Point p{3, 4};. Você também pode atribuir cada campo manualmente com o operador ponto (p.x = 3;), dar valores padrão aos membros na definição (int x = 0;), ou escrever um construtor para que a struct se configure sozinha. A inicialização com chaves é preferida porque não deixa campos sem inicializar de forma silenciosa.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR