Slides utilizados em aula na disciplina Programação Modular do Instituto de Ciências Exatas e Informática - Sistemas de Informação. Pontifícia Universidade Católica de Minas Gerais - Unidade Barreiro, 1º Semestre 2015.
"muitas formas" (poli = muitas, morphos = formas). Em linguagens de programação o polimorfismo costuma ser considerado o terceiro pilar da programação orientada a objetos, depois do encapsulamento e herança. Este termo se refere à possibilidade de criar código capaz de operar sobre valores de tipos distintos.
abaixo em C++. #include <iostream> #include <string> using namespace std; int main() { int i; char c = 'a'; float x; i = c; c = i + 1; x = i; i = x / 7; cout << i; return 0; }
abaixo em C++. #include <iostream> #include <string> using namespace std; int main() { int i; char c = 'a'; float x; i = c; c = i + 1; x = i; i = x / 7; cout << i; return 0; } Saída correta: 13
new Complex(2,3); Complex num2 = new Complex(3,4); // Soma dois números complexos através do operador sobrecarregado (+) Complex sum = num1 + num2; // Imprime os números e a some usando o método ToString sobrescrito Console.WriteLine("Primeiro número complexo: {0}",num1); Console.WriteLine("Segundo número complexo: {0}",num2); Console.WriteLine("A soma dos dois números complexos: {0}",sum); } } public struct Complex { public int real; public int imaginary; public Complex(int real, int imaginary) { this.real = real; this.imaginary = imaginary; } // Declara qual operador a ser sobrecarregado (+) public static Complex operator +(Complex c1, Complex c2) { return new Complex(c1.real + c2.real, c1.imaginary + c2. imaginary); } // Sobrescreve o método ToString para mostrar o número complexo de forma apropriada public override string ToString() { return(String.Format("{0} + {1}i", real, imaginary)); } Saída correta: Primeiro número complexo: 2 + 3i Segundo número complexo: 3 + 4i A soma dos dois números complexos: 5 + 7i
e controle que atuam uniformemente sobre valores de vários tipos. A principal característica desse polimorfismo é a parametrização das estruturas de dados e subprogramas com relação ao tipo do elemento sobre o qual operam." (Flávio Varejão, 2004) Em C# isso é possível através de classes e métodos genéricos. Classes genéricas encapsulam as operações que não são específicos para um determinado tipo de dados. O uso mais comum para as classes genéricas é com coleções como listas encadeadas, tabelas hash, pilhas, filas, árvores, e assim por diante. As operações como adição e remoção de itens da coleção são realizados basicamente da mesma maneira, independentemente do tipo de dados armazenados.
T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; } static void Main(string[] args) { int a = 1; int b = 2; Troca<int>(ref a, ref b); System.Console.WriteLine(a + " " + b); } } Você também pode omitir o argumento de tipo e o compilador conseguirá inferir. Esta chamada poderia ser assim então: Troca(ref a, ref b);
} public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } } } public class GenericList<T> { private class Node { public Node(T t) { next = null; data = t; } private Node next; public Node Next { get { return next; } set { next = value; } } private T data; public T Data { get { return data; } set { data = value; } } } class TestGenericList { static void Main() { GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++) { list.AddHead(x); } foreach (int i in list) { System.Console.Write(i + " "); } System.Console.WriteLine("\nPronto"); } }
} public void AddHead(T t) { Node n = new Node(t); n.Next = head; head = n; } public IEnumerator<T> GetEnumerator() { Node current = head; while (current != null) { yield return current.Data; current = current.Next; } } } public class GenericList<T> { private class Node { public Node(T t) { next = null; data = t; } private Node next; public Node Next { get { return next; } set { next = value; } } private T data; public T Data { get { return data; } set { data = value; } } } Note que T está disponível para a classe Node aninhada. Quando GenericList <t> for instanciada com um tipo concreto, por exemplo: GenericList <int> cada ocorrência de T será substituída por int. class TestGenericList { static void Main() { GenericList<int> list = new GenericList<int>(); for (int x = 0; x < 10; x++) { list.AddHead(x); } foreach (int i in list) { System.Console.Write(i + " "); } System.Console.WriteLine("\nPronto"); } } Saída correta: 9 8 7 6 5 4 3 2 1 0 Done
a objetos. Ele se baseia no uso de uma hierarquia de tipos para criar abstrações de dados e controle polimórficas. A ideia fundamental do polimorfismo por inclusão é que elementos dos subtipos são também elementos do super tipo (daí o nome inclusão). Assim, as abstrações formadas a partir do supertipo podem também envolver elementos dos subtipos." (Flávio Varejão, 2004)
e Outras - Conceitos e Técnicas o autor divide polimorfismo por inclusão nos seguintes subtópicos: • Herança; ◦ Especificador de acesso para classes herdeiras; ◦ Inicialização de atributos com herança; ◦ Sobrescrição; • Identificação dinâmica de tipos; ◦ Ampliação (upcasting); ◦ Estreitamento (downcasting); ◦ Amarração tardia de tipos; ◦ Classes abstratas; • Herança múltipla; • Metaclasses;
Outras - Conceitos e Técnicas o autor divide polimorfismo por inclusão nos seguintes subtópicos: • Herança; ◦ Especificador de acesso para classes herdeiras; ◦ Inicialização de atributos com herança; ◦ Sobrescrição; • Identificação dinâmica de tipos; ◦ Ampliação (upcasting); ◦ Estreitamento (downcasting); ◦ Amarração tardia de tipos; ◦ Classes abstratas; • Herança múltipla; • Metaclasses; inclusão C# não suporta herança múltipla nem metaclasses.
cc1, cc2 = new ConcaCorrente("Bento", 100.00); cb1 = cc2; // upcasting legal // cc1 = cb2; // downcasting ilegal. Descoberto em tempo de compilação. // cc1 = (ContaCorrente)cb2; // downcasting ilegal. Descoberto em tempo de execução. cc1 = (ContaCorrente)cb1; // downcasting legal. cb1 já refere ao tipo Conta Corrente
cc1, cc2 = new ConcaCorrente("Bento", 100.00); cb1 = cc2; // upcasting legal // cc1 = cb2; // downcasting ilegal. Descoberto em tempo de compilação. // cc1 = (ContaCorrente)cb2; // downcasting ilegal. Descoberto em tempo de execução. cc1 = (ContaCorrente)cb1; // downcasting legal. cb1 já refere ao tipo Conta Corrente Como resolver isso?
• typeof : Usado para obter o tipo System.Type de um objeto que é especificado em tempo de compilação. • GetType : O tipo exato em tempo de execução da instância atual. • is : Verifica se um objeto é compatível com um determinado tipo. Retorna true se a instância pertence a árvore de herança. Avalia a compatibilidade do tipo em tempo de execução.
Animal pet2 = new Cachorro(); Gato cat1 = new Gato(); Gato dog1 = new Gato(); Gato cat2 = new Animal(); Cachorro dog1 = new Cachorro(); Cachorro dog2 = new Gato(); Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); Animal pet2 = new Cachorro(); Gato cat1 = new Gato(); Gato dog1 = new Gato(); Gato cat2 = new Animal(); Cachorro dog1 = new Cachorro(); Cachorro dog2 = new Gato(); Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); Gato cat1 = new Gato(); Gato dog1 = new Gato(); Gato cat2 = new Animal(); Cachorro dog1 = new Cachorro(); Cachorro dog2 = new Gato(); Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); ✓ Gato cat1 = new Gato(); ✓ Gato dog1 = new Gato(); ✓ Gato cat2 = new Animal(); X Cachorro dog1 = new Cachorro(); Cachorro dog2 = new Gato(); Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); ✓ Gato cat1 = new Gato(); ✓ Gato dog1 = new Gato(); ✓ Gato cat2 = new Animal(); X Cachorro dog1 = new Cachorro(); ✓ Cachorro dog2 = new Gato(); Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); ✓ Gato cat1 = new Gato(); ✓ Gato dog1 = new Gato(); ✓ Gato cat2 = new Animal(); X Cachorro dog1 = new Cachorro(); ✓ Cachorro dog2 = new Gato(); X Cachorro dog3 = new Animal(); Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); ✓ Gato cat1 = new Gato(); ✓ Gato dog1 = new Gato(); ✓ Gato cat2 = new Animal(); X Cachorro dog1 = new Cachorro(); ✓ Cachorro dog2 = new Gato(); X Cachorro dog3 = new Animal(); X Cachorro cat4 = new Cachorro(); public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício
Gato(); ✓ Animal pet2 = new Cachorro(); ✓ Gato cat1 = new Gato(); ✓ Gato dog1 = new Gato(); ✓ Gato cat2 = new Animal(); X Cachorro dog1 = new Cachorro(); ✓ Cachorro dog2 = new Gato(); X Cachorro dog3 = new Animal(); X Cachorro cat4 = new Cachorro(); ✓ public class Animal { private String nome; public String getName(){ return this.nome; } public virtual void FazerBarulho() { } } public class Gato : Animal { public override void FazerBarulho(){ Console.WriteLine("Miau!"); } } public class Cachorro : Animal { public override void FazerBarulho() { Console.WriteLine("Auau!"); } } exercício