image

Access unlimited bootcamps and 650+ courses forever

60
%OFF
Article image
Carlos Santos
Carlos Santos20/10/2025 20:04
Share

Orientação a objetos em C#: entenda de forma simples e prática

    Se você está começando na carreira como desenvolvedor C#, dominar orientação a objetos é um passo fundamental.

    Esse paradigma de programação não é apenas uma forma de codificar— é uma maneira de pensar o código de forma mais organizada, reutilizável e escalável.

    Neste artigo, você vai entender como aplicar, na prática, os quatro pilares da orientação a objetos em C# com exemplos diretos e comentados.

    O que é orientação a objetos e por que ela é fundamental em C#

    De maneira simples, a orientação a objetos (OO) organiza o software em objetos — pequenas unidades que representam entidades do mundo real ou conceitos abstratos.

    Cada objeto combina atributos (dados) e métodos (comportamentos), tornando o código mais próximo da lógica humana e mais fácil de manter.

    Em C#, a OO é parte da base da linguagem.

    Ao dominar esses conceitos, você ganha clareza, modularidade e capacidade de expansão do código — habilidades fundamentais para o mercado de trabalho.

    Classes e objetos: a base da orientação a objetos em C#

    Toda aplicação orientada a objetos começa com classes e objetos.

    Uma classe define o modelo — a estrutura e o comportamento — enquanto o objeto é a instância real que atua no código.

    Veja este exemplo com a classe Pessoa:

    // Instancia um novo objeto da classe Pessoa
    Pessoa pessoa1 = new Pessoa();
    
    
    // Define o valor da propriedade Nome
    pessoa1.Nome = "Carlos";
    
    
    // Define o valor da propriedade Idade
    pessoa1.Idade = 29;
    
    
    // Chama o método Apresentar() que exibe a mensagem no console
    pessoa1.Apresentar();
    
    
    // Classe que representa uma pessoa com propriedades básicas
    public class Pessoa
    {
      // Propriedade para armazenar o nome
      public string Nome { get; set; }
    
    
      // Propriedade para armazenar a idade
      public int Idade { get; set; }
    
    
      // Método para apresentar uma pessoa
      public void Apresentar()
      {
          Console.WriteLine($"Olá, meu nome é {Nome} e tenho {Idade} anos.");
      }
    }
    

    No código acima, cada objeto criado a partir da classe Pessoa pode ter valores diferentes. Seria possível criar várias instâncias chamadas de pessoa2, pessoa3, etc, utilizando o mesmo modelo — ou seja, a classe Pessoa. É isso que torna o código flexível e dinâmico.

    Abstração: focando no essencial

    A abstração permite esconder detalhes complexos e trabalhar apenas com o que é realmente importante.

    Em C#, isso é feito com classes abstratas e interfaces — estruturas que definem o que deve ser feito, sem especificar como.

    // Cria um retângulo e calcula sua área
    Retangulo retangulo = new Retangulo();
    retangulo.Largura = 5.0;
    retangulo.Altura = 3.0;
    
    // Chama o método CalcularArea() e exibe o resultado
    double area = retangulo.CalcularArea();
    Console.WriteLine($"A área do retângulo é: {area}");
    
    // Polimorfismo: podemos usar a classe base como tipo
    Forma forma = new Retangulo { Largura = 4.0, Altura = 6.0 };
    Console.WriteLine($"Área usando polimorfismo: {forma.CalcularArea()}");
    public abstract class Forma
    {
      // Método abstrato que obriga as classes derivadas a implementarem
      // o cálculo da área de acordo com suas características específicas
      public abstract double CalcularArea();
    }
    
    // Classe Retangulo herda de Forma (indicado pelo símbolo :)
    // Deve obrigatoriamente implementar todos os métodos abstratos da classe pai
    public class Retangulo : Forma
    {
      // Propriedade que armazena a largura do retângulo
      public double Largura { get; set; }
    
      // Propriedade que armazena a altura do retângulo
      public double Altura { get; set; }
    
      // Implementação do método abstrato
      // Override indica que estamos sobrescrevendo o método da classe base
      public override double CalcularArea() => Largura * Altura;
    }
    

    No código acima, a classe Forma representa o conceito geral, enquanto Retangulo implementa os detalhes. Por se tratar de um conceito (abstração), a classe Forma não pode ser instanciada diretamente. Essa separação traz organização e clareza, principalmente em projetos grandes.

    Encapsulamento: protegendo seus dados

    O encapsulamento garante que os dados de um objeto sejam acessados e modificados de forma correta e segura.

    Isso reduz erros e melhora a segurança do código.

    Observe o seguinte código:

    // Cria uma nova conta bancária
    ContaBancaria conta = new ContaBancaria();
    
    // Exibe o saldo inicial (será 0.0 por padrão)
    Console.WriteLine($"Saldo inicial: R$ {conta.Saldo}");
    
    // Realiza um depósito válido
    conta.Depositar(100.50);
    Console.WriteLine($"Saldo após depósito de R$ 100,50: R$ {conta.Saldo}");
    
    // Tenta depositar um valor inválido
    conta.Depositar(-50);
    Console.WriteLine($"Saldo após tentar depositar R$ -50: R$ {conta.Saldo}");
    
    // Realiza outro depósito válido
    conta.Depositar(250.75);
    Console.WriteLine($"Saldo final: R$ {conta.Saldo}");
    
    // Classe que representa uma conta bancária básica
    public class ContaBancaria
    {
      // Campo privado que armazena o saldo real da conta
      // A palavra private garante que só pode ser acessado dentro da classe
      private double saldo;
    
      // Propriedade pública que controla o acesso ao saldo
      public double Saldo
      {
          // Qualquer código pode ler o saldo
          get { return saldo; }
    
          // Set privado: somente os métodos da classe podem modificar o saldo diretamente
          private set { saldo = value; }
      }
    
      // Método público para depositar dinheiro na conta
      public void Depositar(double valor)
      {
          // Valida se o valor é positivo antes de adicionar ao saldo
          if (valor > 0)
          {
              // Usa a propriedade Saldo para adicionar o valor
              // Internamente, acessa o setter privado que modifica o campo saldo
              Saldo += valor;
          }
      }
    }
    

    Aqui, saldo não pode ser alterado diretamente de fora da classe. Para que isso seja possível, é necessário utilizar um getter — que retorna o valor de forma indireta quando Saldo é invocado num objeto. 

    Além disso, não é possível atribuir qualquer valor sem antes passar pela validação do setter — o que previne que valores errados sejam atribuídos nos campos privados do objeto. Resumindo, somente os métodos da própria classe podem modificar seu valor, garantindo controle e consistência.

    Herança: reaproveitando e estendendo o código

    A herança permite que uma classe herde atributos e métodos de outra, evitando duplicação e facilitando a manutenção.

    Em C#, usamos : para indicar herança.

    Veja um exemplo:

    // Cria um objeto Carro usando inicializador de objeto { }
    // Esta sintaxe permite definir as propriedades durante a criação
    Carro meuCarro = new Carro
    {
      Modelo = "Sedan",        // Propriedade herdada de Veiculo
      NumeroPortas = 4         // Propriedade específica de Carro
    };
    
    // Chama o método Ligar() que foi herdado da classe Veiculo
    // Mesmo não estando definido na classe Carro, está disponível pela herança
    meuCarro.Ligar();
    
    // Exibe as informações do carro
    Console.WriteLine($"Modelo: {meuCarro.Modelo}");
    Console.WriteLine($"Número de portas: {meuCarro.NumeroPortas}");
    
    // Demonstração adicional: criando um veículo genérico
    Veiculo veiculo = new Veiculo { Modelo = "Genérico" };
    veiculo.Ligar();
    // veiculo.NumeroPortas causaria erro - propriedade não existe em Veiculo
    
    // Classe base que representa um veículo genérico
    public class Veiculo
    {
      // Propriedade que armazena o modelo do veículo
      public string Modelo { get; set; }
    
      // Método que simula a ação de ligar o veículo
      public void Ligar() => Console.WriteLine("Veículo ligado!");
    }
    
    // Classe Carro herda todas as propriedades e métodos públicos da classe Veiculo
    public class Carro : Veiculo
    {
      // Propriedade específica da classe Carro
      // Não existe na classe base Veiculo
      public int NumeroPortas { get; set; }
    }
    

    No exemplo acima, Veiculo é utilizada como base pela classe que a herda — nesse caso Carro. Isso implica dizer que o que já foi implementado na superclasse (Veiculo) pode ser aproveitado diretamente.

    Em outras palavras, com a herança, você pode criar uma hierarquia de classes bem estruturada — reutilizando código e facilitando a evolução do sistema

    Polimorfismo: comportamento dinâmico e flexível

    O polimorfismo permite tratar objetos diferentes de forma uniforme, mantendo a flexibilidade do código.

    Em C#, isso é feito com override ou sobrecarga de métodos.

    // Demonstração de polimorfismo:
    // Declaramos a variável como tipo Animal (classe base),
    // mas instanciamos um objeto Cachorro (classe derivada)
    Animal meuCachorro = new Cachorro();
    
    // Ao chamar EmitirSom(), é usado o método da classe REAL do objeto (Cachorro)
    // e não da classe declarada (Animal) 
    meuCachorro.EmitirSom(); // Saída: Au Au!
    
    // Comparação: criando um animal genérico
    Animal animal = new Animal();
    animal.EmitirSom(); // Saída: Som genérico
    
    // Array de animais com polimorfismo
    Animal[] animais = new Animal[]
    {
                  new Animal(),      // Som genérico
                  new Cachorro(),    // Au Au!
                  new Cachorro()     // Au Au!
    };
    
    Console.WriteLine("\nDemonstrando polimorfismo com múltiplos animais:");
    
    foreach (Animal a in animais)
    {
      a.EmitirSom();
    }
    
    // Classe base que representa um animal genérico
    public class Animal
    {
      // Método virtual que pode ser sobrescrito pelas classes derivadas
      // A palavra-chave 'virtual' permite que classes filhas tenham sua própria implementação
      public virtual void EmitirSom() => Console.WriteLine("Som genérico");
    }
    
    // Classe Cachorro herda de Animal
    public class Cachorro : Animal
    {
      // Sobrescreve o método EmitirSom() da classe base
      // 'override' indica a substituição da implementação do método virtual da classe pai
      public override void EmitirSom() => Console.WriteLine("Au Au!");
    }
    

    No código acima, o método virtual EmitirSom() da classe Animal pode ser sobrescrito (ou alterado) para que sirva os propósitos da classe Cachorro, que, por sua vez, utiliza a palavra-chave override para fazer a mudança necessária.

    Dito de outro modo, o polimorfismo torna o código adaptável — o que garante fazer pequenos ajustes quando necessário, mas sem alterar toda a estrutura de uma classe.

    Exemplo prático: mini sistema de funcionários

    Veja como os quatro pilares da orientação a objetos em C# trabalham juntos neste exemplo:

    // POLIMORFISMO: Mesma variável tipo base, objetos diferentes
    Funcionario f1 = new Gerente { Nome = "Alice", Bonus = 1000 };
    Funcionario f2 = new Vendedor { Nome = "Marcos", Comissao = 500 };
    
    // POLIMORFISMO: Mesmo método, comportamentos diferentes
    f1.ExibirInfo();  // Chama a versão de Gerente
    f2.ExibirInfo();  // Chama a versão de Vendedor
    
    Console.WriteLine($"\nTotal da folha: R${(f1.CalcularSalario() + f2.CalcularSalario()):F2}");
    
    public abstract class Funcionario
    {
      // ENCAPSULAMENTO: Campo privado com propriedade pública
      private string _nome;
    
      public string Nome
      {
          get => _nome;
          set
          {
              if (!string.IsNullOrWhiteSpace(value))
                  _nome = value;
          }
      }
    
      // ABSTRAÇÃO: Método abstrato - cada tipo implementa sua lógica
      public abstract decimal CalcularSalario();
    
      // Método para exibir informações (pode ser sobrescrito)
      public virtual void ExibirInfo()
      {
          Console.WriteLine($"{Nome} recebe R${CalcularSalario():F2}");
      }
    }
    
    // HERANÇA: Gerente herda de Funcionario
    public class Gerente : Funcionario
    {
      // ENCAPSULAMENTO: Controla acesso ao bônus
      private decimal _bonus;
    
      public decimal Bonus
      {
          get => _bonus;
          set => _bonus = value >= 0 ? value : 0;
      }
    
      // POLIMORFISMO: Implementação específica de CalcularSalario()
      public override decimal CalcularSalario() => 5000 + Bonus;
    
      // POLIMORFISMO: Sobrescreve comportamento do método base
      public override void ExibirInfo()
      {
          Console.WriteLine($"{Nome} (Gerente) recebe R${CalcularSalario():F2} " +
                           $"(Salário: R${CalcularSalario()-Bonus:F2} + Bônus: R${Bonus})");
      }
    }
    
    // HERANÇA: Vendedor herda de Funcionario
    public class Vendedor : Funcionario
    {
      // ENCAPSULAMENTO: Controla o acesso à comissão
      private decimal _comissao;
    
      public decimal Comissao
      {
          get => _comissao;
          set => _comissao = value >= 0 ? value : 0;
      }
    
      // POLIMORFISMO: Implementação específica de CalcularSalario
      public override decimal CalcularSalario() => 3000M + Comissao;
    
      // POLIMORFISMO: Sobrescreve comportamento do método base
      public override void ExibirInfo()
      {
          Console.WriteLine($"{Nome} (Vendedor) recebe R${CalcularSalario():F2} " +
                           $"(Salário: R${CalcularSalario()-Comissao:F2} + Comissão: R${Comissao})");
      }
    }
    

    O mini sistema acima demonstra os conceitos da orientação a objetos de forma integrada — exatamente como acontece em aplicações reais. Observe como os quatro conceitos são orquestrados para que o código seja reutilizado e protegido ao mesmo tempo.

    Dicas práticas para dominar orientação a objetos em C#

    • Comece pequeno: pratique com classes simples e depois evolua para sistemas completos.
    • Use propriedades em vez de campos públicos: isso mantém o controle sobre os dados.
    • Abstraia comportamentos comuns: use interfaces para definir contratos claros.
    • Analise projetos reais: explore repositórios no GitHub com código C# orientado a objetos.
    • Refatore com frequência: OO é sobre evolução constante do design.

    Conclusão: transforme a orientação a objetos em seu diferencial

    Dominar os pilares da orientação a objetos em C# é mais do que entender teoria — é dar o próximo passo na sua jornada como desenvolvedor.

    Quando você aplica abstração, encapsulamento, herança e polimorfismo, o código deixa de ser apenas funcional e passa a refletir a sua forma de pensar: organizada, clara e profissional.

    Cada linha escrita é uma chance de evoluir. Cada erro, uma lição. Cada refatoração, um avanço.

    💡 Não espere o momento perfeito — comece agora.

    Pegue um projeto, aplique um conceito e veja como o seu código (e você) podem se transformar a cada dia.

    GitHub: https://github.com/CarlosDi96/artigos-exemplos-de-codigo/tree/main/POOBasico 

    Share
    Recommended for you
    Cognizant - Mobile Developer
    Luizalabs - Back-end com Python
    PcD Tech Bradesco - Java & QA Developer
    Comments (0)