Classes e Campos: Criando seu Primeiro Molde

Classes e Campos: Criando seu Primeiro Molde

A classe como molde e o objeto como exemplar: como definir uma classe com seus campos, criar objetos a partir dela com new e acessar seus dados pelo ponto. A aula fecha com o encontro entre objetos e coleções, guardando registros completos numa lista e percorrendo-os com laço.
Linguagem C#

• • 11 min de leitura

Na aula anterior, assentamos a ideia: objetos agrupam características numa unidade que modela uma coisa, e classes são os moldes que definem esses objetos. Agora tornamos isso concreto. Nesta aula, você criará sua primeira classe — o molde de um tipo de coisa —, definirá suas características (chamadas campos), e aprenderá a criar objetos a partir dela. Pela primeira vez no curso, você escreverá um tipo de sua própria autoria, em vez de usar apenas os tipos prontos da linguagem (como int, string, List). É um marco: você deixa de ser apenas consumidor de tipos e passa a ser criador deles. Retomando a analogia do formulário, esta é a aula em que você desenha o formulário em branco e depois o preenche.

Definindo uma classe

Vamos criar uma classe para representar uma pessoa. A definição de uma classe usa a palavra-chave class, seguida do nome da classe e de um bloco de chaves que contém suas características:

class Pessoa
{
    // Campos: as características que toda pessoa terá.
    public string Nome;
    public int Idade;
    public string Cidade;
}

Vamos entender cada parte. A palavra class anuncia que estamos definindo um molde de objeto. Pessoa é o nome da classe — e note a convenção: nomes de classe começam com letra maiúscula (como Pessoa, Produto, ContaBancaria), o que os distingue das variáveis (minúsculas) e os aproxima, na aparência, dos tipos prontos como Console. Dentro do bloco, declaramos os campos — as características que todo objeto desta classe terá. Cada campo é declarado quase como uma variável comum (tipo e nome), com o acréscimo da palavra public à frente, que por ora significa "esta característica pode ser acessada de fora do objeto" (voltaremos ao significado pleno de public numa aula futura sobre encapsulamento).

Repare no que essa classe é e no que ela não é. Ela é o molde: define que toda pessoa terá um nome (texto), uma idade (inteiro) e uma cidade (texto). Ela não é, ela própria, nenhuma pessoa específica — assim como o formulário em branco não é ninguém. Nenhum dado concreto ("Ana", 30) aparece aqui; apenas a estrutura que as pessoas concretas terão. Definir a classe é desenhar o formulário; ainda não preenchemos nenhum.

Onde colocar a classe

Uma questão prática: onde, no seu arquivo, essa definição de classe deve ficar? Em um programa simples de console, você pode colocar a definição da classe ao final do arquivo Program.cs, depois das instruções principais, ou em um arquivo separado. Por ora, para nossos exemplos, colocá-la ao final do arquivo funciona bem — o C# encontra a definição independentemente de onde ela esteja no arquivo. (Em projetos maiores, a convenção é dar a cada classe seu próprio arquivo, com o nome da classe, mas isso é uma questão de organização que abordaremos adiante; agora, foquemos no conceito.)

Criando objetos a partir da classe

Definido o molde, criamos objetos concretos a partir dele — preenchemos os formulários. Para criar um objeto de uma classe, usamos a palavra new (a mesma que usamos para criar arrays e listas), seguida do nome da classe:

// Cria um objeto Pessoa concreto e o guarda na variável 'p1':
Pessoa p1 = new Pessoa();

// Preenche suas características (os campos), acessadas com o ponto:
p1.Nome = "Ana";
p1.Idade = 30;
p1.Cidade = "Recife";

Acompanhe. A linha Pessoa p1 = new Pessoa(); faz duas coisas: new Pessoa() cria um novo objeto-pessoa (um formulário em branco recém-impresso), e Pessoa p1 = guarda esse objeto na variável p1. Note que o tipo da variável é Pessoa — a classe que você criou agora é um tipo, usável exatamente como int ou string. Em seguida, preenchemos os campos do objeto com o ponto: p1.Nome = "Ana" guarda "Ana" no campo Nome daquele objeto específico. O ponto, mais uma vez, significa "acesse algo de dentro deste objeto" — o mesmo ponto de nome.Length e tarefas.Add, agora aplicado ao seu próprio tipo.

O poder da classe como molde fica evidente quando criamos vários objetos. Cada um é independente, com seus próprios valores, mas todos compartilham a mesma estrutura:

Pessoa p2 = new Pessoa();
p2.Nome = "Beto";
p2.Idade = 25;
p2.Cidade = "Olinda";

// p1 e p2 são pessoas DIFERENTES, cada uma com seus próprios dados:
Console.WriteLine(p1.Nome);   // Ana
Console.WriteLine(p2.Nome);   // Beto

p1 e p2 são dois objetos distintos, dois formulários preenchidos diferentes, criados do mesmo molde Pessoa. Alterar o nome de p1 não afeta p2 — cada objeto guarda seus próprios valores em seus próprios campos. Uma classe, muitos objetos independentes: eis a virada da aula anterior, agora concreta em código.

Usando os campos

Uma vez preenchidos, os campos de um objeto se usam como quaisquer valores — você os lê, exibe, combina em expressões, tudo acessando-os pelo ponto a partir do objeto:

Pessoa p = new Pessoa();
p.Nome = "Carla";
p.Idade = 42;
p.Cidade = "Caruaru";

// Lendo os campos numa mensagem interpolada:
Console.WriteLine($"{p.Nome} tem {p.Idade} anos e mora em {p.Cidade}.");

// Usando um campo numa expressão e numa decisão:
Console.WriteLine($"Ano que vem terá {p.Idade + 1} anos.");
if (p.Idade >= 18)
    Console.WriteLine($"{p.Nome} é maior de idade.");

Repare como p.Idade se comporta exatamente como uma variável int — pode entrar em p.Idade + 1, em comparações, em condições. A diferença é apenas que ele pertence ao objeto p, acessado pelo ponto. As características do objeto são valores como quaisquer outros; o que muda é que agora estão organizadas dentro de uma coisa coesa, em vez de flutuarem soltas.

Objetos em coleções: o encontro de duas ideias

Um momento particularmente gratificante é combinar objetos com as coleções da fase anterior. Lembra que dissemos que as coleções guardavam valores simples? Elas guardam qualquer tipo — inclusive os seus próprios. Uma List<Pessoa> guarda pessoas:

List<Pessoa> pessoas = new();

Pessoa a = new Pessoa();
a.Nome = "Ana"; a.Idade = 30; a.Cidade = "Recife";
pessoas.Add(a);

Pessoa b = new Pessoa();
b.Nome = "Beto"; b.Idade = 25; b.Cidade = "Olinda";
pessoas.Add(b);

// Percorremos as pessoas com foreach, como qualquer coleção:
foreach (Pessoa pessoa in pessoas)
{
    Console.WriteLine($"{pessoa.Nome}, {pessoa.Idade} anos, de {pessoa.Cidade}");
}

Aqui as duas grandes ideias das últimas fases se encontram: coleções (Fase 4) que guardam objetos (Fase 5). Agora você pode ter uma lista de pessoas, de produtos, de qualquer coisa que modelar, e processá-la com os laços e padrões que já domina. Aquele problema do "emaranhado de variáveis" da aula anterior — nome1, idade1, nome2, idade2... — está resolvido: uma List<Pessoa> guarda quantas pessoas você quiser, cada uma uma unidade coesa, percorrível com um simples foreach. É a demonstração de por que os objetos valem o esforço.

A ideia de objeto ganhou forma concreta. Uma classe é o molde que descreve quais características uma coisa tem, e cada objeto criado a partir dela é um exemplar independente, com seus próprios valores. Definir a classe, instanciar objetos com new e acessar seus campos pelo ponto são as três operações que sustentam tudo o que vem depois.

O encontro entre objetos e coleções é onde a utilidade salta aos olhos: uma lista de objetos permite manter dezenas de registros completos, cada um com todos os seus dados juntos, e percorrê-los com as mesmas técnicas já conhecidas. É a partir daí que os programas começam a se parecer com sistemas reais.

Fontes e leituras recomendadas

Exercícios

Exercício 1

Crie uma classe Produto com três campos públicos: Nome (texto), Preco (decimal) e Estoque (inteiro). Depois, crie um objeto Produto, preencha seus campos, e exiba-os numa mensagem interpolada. Explique a diferença entre definir a classe e criar um objeto dela.

Ver resposta

✓ Resposta: Exemplo:

Produto p = new Produto();
p.Nome = "Caderno";
p.Preco = 12.50m;
p.Estoque = 100;
Console.WriteLine($"{p.Nome}: R$ {p.Preco}, {p.Estoque} em estoque.");

class Produto
{
    public string Nome;
    public decimal Preco;
    public int Estoque;
}

Definir a classe Produto cria o molde: estabelece que todo produto terá nome, preço e estoque, sem ser nenhum produto específico. Criar um objeto (new Produto()) produz um produto concreto, preenchível com dados próprios. A definição é a estrutura; o objeto é uma instância concreta com valores.

Exercício 2

Usando a classe Produto do exercício anterior, crie dois objetos diferentes, com dados distintos, e exiba os campos de ambos. Demonstre, alterando um campo de um dos objetos, que a mudança não afeta o outro. Explique por que eles são independentes.

Ver resposta

✓ Resposta: Exemplo:

Produto a = new Produto();
a.Nome = "Caneta"; a.Preco = 2m; a.Estoque = 50;
Produto b = new Produto();
b.Nome = "Borracha"; b.Preco = 1.5m; b.Estoque = 30;
a.Estoque = 45;   // altera só o objeto 'a'
Console.WriteLine($"{a.Nome}: {a.Estoque}");   // Caneta: 45
Console.WriteLine($"{b.Nome}: {b.Estoque}");   // Borracha: 30 (inalterado)

Alterar a.Estoque não afetou b, porque a e b são objetos distintos, cada um com seus próprios campos guardando seus próprios valores. Embora compartilhem a mesma estrutura (vieram do mesmo molde Produto), são cópias preenchidas independentes.

Exercício 3

Crie uma classe Livro com campos apropriados (por exemplo, Titulo, Autor, Ano). Crie três objetos Livro, adicione-os a uma List<Livro>, e percorra a lista com um foreach, exibindo os dados de cada livro. Comente como isso resolve o problema dos "valores soltos" da Aula #22.

Ver resposta

✓ Resposta: Exemplo:

List<Livro> livros = new();
Livro l1 = new Livro(); l1.Titulo = "Dom Casmurro"; l1.Autor = "Machado"; l1.Ano = 1899;
livros.Add(l1);
Livro l2 = new Livro(); l2.Titulo = "1984"; l2.Autor = "Orwell"; l2.Ano = 1949;
livros.Add(l2);
Livro l3 = new Livro(); l3.Titulo = "O Cortiço"; l3.Autor = "Aluísio"; l3.Ano = 1890;
livros.Add(l3);
foreach (Livro livro in livros)
    Console.WriteLine($"{livro.Titulo}, de {livro.Autor} ({livro.Ano})");

class Livro { public string Titulo; public string Autor; public int Ano; }

Isso resolve o problema dos valores soltos porque cada livro é uma unidade coesa (título, autor e ano juntos, pertencendo ao mesmo objeto), e a List<Livro> guarda todos eles ordenadamente, percorríveis com um único foreach — em vez de dezenas de variáveis soltas (titulo1, autor1, titulo2...) sem relação estrutural entre si.

Exercício 4

Explique, com suas palavras, o papel da palavra new na linha Pessoa p = new Pessoa();. O que exatamente é criado, e o que a variável p passa a guardar?

Ver resposta

✓ Resposta: A palavra new em Pessoa p = new Pessoa(); cria um novo objeto da classe Pessoa — um novo formulário em branco recém-impresso, com seus campos prontos para serem preenchidos. A parte Pessoa p = guarda esse objeto recém-criado na variável p. Assim, após essa linha, p passa a guardar uma referência a um objeto-pessoa concreto e independente, que podemos então preencher e usar acessando seus campos com o ponto.

Exercício 5

Sem código: retomando a analogia do formulário, explique o que, no código desta aula, corresponde ao "formulário em branco" e o que corresponde ao "formulário preenchido". Por que faz sentido dizer que a classe é definida uma vez, mas os objetos podem ser criados muitas vezes?

Ver resposta

✓ Resposta: Na analogia, o formulário em branco corresponde à classe (class Pessoa {...}): a definição do molde, com os campos rotulados mas sem dados. O formulário preenchido corresponde a cada objeto criado com new e preenchido com valores (p1 com "Ana", 30, "Recife"). Faz sentido dizer que a classe é definida uma vez porque o molde precisa existir apenas uma vez para servir de base a todas as cópias; e os objetos podem ser criados muitas vezes porque, a partir desse único molde, produzimos quantas instâncias concretas quisermos, cada uma com seus próprios dados, do mesmo modo que um único formulário em branco pode ser fotocopiado e preenchido inúmeras vezes com informações diferentes.

Comentários

Mais em Linguagem C#

Conversando com o Usuário: Entrada e Saída
Conversando com o Usuário: Entrada e Saída

Como fazer o programa conversar com quem o usa: exibir informação com…

Métodos de Objeto e a Palavra this
Métodos de Objeto e a Palavra this

Como dar comportamento aos objetos: métodos que operam sobre o estado do…

Projeto: Um Sistema de Formas de Pagamento
Projeto: Um Sistema de Formas de Pagamento

Um projeto integrador que reúne toda a fase de objetos num sistema de formas…