Já ficou confuso tentando entender de uma vez o polimorfismo em OOP, do overriding aos protocolos?
Overloading, overriding e protocolos podem parecer semelhantes, então é fácil confundi-los.
Vamos direto à conclusão: polimorfismo é quando “uma chamada com o mesmo nome se comporta de forma diferente dependendo do alvo”. O overriding implementa isso por herança, enquanto os protocolos implementam por meio de um contrato.
Neste artigo, vou explicar passo a passo como esses três conceitos se relacionam.
O que exatamente é polimorfismo?
Polimorfismo (Polymorphism) vem do grego e significa “muitas (poly) formas (morph)”.
Em termos simples, é a capacidade de objetos diferentes responderem de formas diferentes à mesma mensagem.
Por exemplo, mesmo recebendo a mesma ordem, o cachorro late e o gato mia quando você diz “faça um som”.
Quem chama só precisa invocar 소리내(). Cada objeto decide o que vai produzir.
O ponto central do polimorfismo é que “quem chama não precisa saber”.
Assim, qualquer objeto pode ser tratado com o mesmo código.
Isso deixa o código muito mais flexível. Adicionar um novo animal não exige alterar o código de chamada.
Overloading e overriding: qual é a diferença?
Os nomes parecidos são o principal motivo da confusão.
Overloading é criar várias funções com o mesmo nome, alterando apenas os parâmetros.
Overriding é quando uma classe filha redefine e sobrescreve uma função criada pela classe pai.
Como só falar pode ser difícil, vamos ver isso no código.
class Animal {
func sound() { print("...") }
}
class Dog: Animal {
override func sound() { print("Au au") } // Overriding
}
let a: Animal = Dog()
a.sound()
// Saída: Au au
O interessante é que, mesmo que o tipo de a seja Animal, ele produz o som de Dog.
Esse é o polimorfismo decidido em tempo de execução ao observar o objeto real.
Overloading é um pouco diferente. A função a ser chamada é escolhida em tempo de compilação.
func add(_ a: Int, _ b: Int) -> Int { a + b }
func add(_ a: String, _ b: String) -> String { a + b }
print(add(1, 2)) // Saída: 3
print(add("a", "b")) // Saída: ab
Por isso, overloading também é chamado de polimorfismo estático, e overriding, de polimorfismo dinâmico.
Por que precisamos de protocolos?
A herança já permite polimorfismo, então por que os protocolos existem?
Herança representa uma relação “is-a”, então só pode haver uma classe pai. É difícil um gato ser um animal e, ao mesmo tempo, pertencer a outra hierarquia.
Um protocolo é muito mais flexível: qualquer tipo pode participar se cumprir o contrato.
protocol Soundable {
func sound()
}
struct Cat: Soundable {
func sound() { print("Miau") }
}
struct Car: Soundable {
func sound() { print("Buzina") }
}
let things: [Soundable] = [Cat(), Car()]
things.forEach { $0.sound() }
// Saída: Miau
// Saída: Buzina
Um gato e um carro não têm nenhuma relação de herança. Ainda assim, podem ficar no mesmo array e ser tratados da mesma forma.
Obter polimorfismo sem uma árvore de herança: esse é o poder dos protocolos.
É também por isso que linguagens como Swift priorizam protocolos em vez de herança.
Quando usar herança e quando usar protocolos
Resumi em uma tabela os critérios que uso na prática.
| Situação | Decisão |
|---|---|
| Quero herdar código comum | Herança (overriding) |
| Não há relação, mas quero garantir o mesmo comportamento | Protocolo |
| Quero atribuir várias características ao mesmo tempo | Protocolo (é possível adotar vários) |
| Quero dar polimorfismo a um tipo por valor (struct) | Protocolo |
Basta lembrar alguns princípios simples.
- Use herança quando quiser reutilizar boa parte da implementação do pai.
- Use um protocolo quando quiser definir uma “capacidade”.
- Se a extensibilidade for uma preocupação, considere primeiro os protocolos.
É assim que perguntam em entrevistas
Q. Explique a diferença entre overloading e overriding.
Overloading define parâmetros diferentes com o mesmo nome e é decidido em tempo de compilação. Overriding é quando uma classe filha redefine um método herdado, com decisão em tempo de execução baseada no objeto real. Por isso, o primeiro é chamado de polimorfismo estático e o segundo, de polimorfismo dinâmico.
Q. Quais são as vantagens de usar protocolos em vez de herança?
A herança é limitada a uma classe pai e não pode ser usada com tipos por valor, enquanto um tipo pode adotar vários protocolos, que também podem ser aplicados a structs. Até tipos sem relação podem ser agrupados e tratados pelo mesmo contrato, o que favorece a extensão.
O polimorfismo pode parecer abstrato no início, mas, se você guardar uma frase — “quem chama não precisa saber” —, o restante fica muito mais claro.
Experimente no código o overriding e os protocolos que você aprendeu hoje. Eles vão ficar muito mais naturais. Boa sorte!

