Baixe o app para aproveitar ainda mais
Prévia do material em texto
Sobrecarga de Funções, Construtores e Operadores Profa. Dra. Ieda Hidalgo E-mail: iedahidalgo@ft.unicamp.br Sobrecarga de Funções ou Métodos Sobrecarregar funções significa utilizar funções com o mesmo nome (funções homônimas), mas com a lista de parâmetros diferente em número e/ou em tipo. Para sobrecarregar uma função, simplesmente declare diferentes versões dela. O sobrecarregamento de funções é uma maneira através da qual C++ obtém o polimorfismo estático. A sobrecarga permite que conjuntos relacionados de funções sejam acessados usando um nome comum. Usando sobrecarga, é possível definir versões ligeiramente diferentes (ou especializadas) para os tipos de dados sobre os quais as funções operam. Leka Highlight Leka Highlight Leka Highlight Exemplos Funções sobrecarregadas Corpo das funções Chamadas às funções int neg (int n); int neg (int n) { return –n; } neg (-10); double neg (double n); double neg (double n) { return –n; } neg (11,23); Leka Highlight Leka Highlight Funções sobrecarregadas Corpo das funções Chamadas às funções int min (int a, int b); int min (int a, int b) { if (a < b) return a; else return b; } min (9,3); char min (char a, char b); char min (char a, char b) { if (tolower(a) < tolower(b)) return a; else return b; } min (‘x’, ‘a’); Seleção da Função O compilador reconhece qual função você quer acessar, verificando o número e tipo dos parâmetros no momento da chamada da função. Restrições na Sobrecarga de Funções �Somente a diferenciação nos nomes dos parâmetros é insuficiente. �Somente alterar o tipo de retorno da função é insuficiente. �Somente alterar a forma de passagem do parâmetro (de valor para referência) é insuficiente. �Cuidado com parâmetros default. Exemplo Sobrecarga • void impres (int, float, char); • void impres (int, float); • Confusão para o compilador • void impres (int, float, char=‘\n’); • void impres (int, float); Conversões Automáticas ou Implícitas de Tipos (Coerção) Se não houver uma correspondência direta entre um parâmetro e um argumento o C++ fará (quando possível) conversões automáticas de tipo. Funções sobrecarregadas Variáveis Chamadas às funções void f (int x); short s = 99; f (s); void f (double x); float r = 11.5F; f (r); Em linguagens que suportam coerção, o código abaixo funciona. procedure soma(float a; float b) {...} int c; float d; soma(c, d); Se não houvesse coerção, você teria que definir diversos tipos com nomes diferentes, mas implementações similares: procedure soma1(a: float; b: float){..}; procedure soma2(a: int; b: float){..}; procedure soma3(a: float; b: int){..}; procedure soma4(a: int; b: int){..}; Situação Ambígua Quando o compilador não consegue escolher corretamente entre duas ou mais funções sobrecarregadas dizemos que a situação é ambígua. Programas contendo ambigüidade não compilarão. Funções sobrecarregadas Chamada às funções float myfunc (float i); Envolvendo conversão de tipo myfunc(10); // que versão de myfunc usar? double myfunc (double i); void saida (int); Envolvendo parâmetros default saida (10); // que versão de saída usar ? void saida (int, int = 0); Sobrecarga de Construtores Sobrecarga de Construtores Para sobrecarregar um construtor, basta declarar as várias formas que ele adotará. Construtor Chamada ao construtor Sample () {x = y = 0;} Sample a; Sample (int i) {x = y = i;} Sample b (5); Sample (int i, int j) {x = i; y = j;} Sample c (9,10); Vantagens da Sobrecarga de Construtores � Eles adicionam flexibilidades às classes, permitindo que um objeto seja construído de várias maneiras. � Eles oferecem conveniência para o usuário da classe ao permitir que um objeto seja construído da maneira mais natural para uma tarefa em particular. � Ao definir tanto um construtor default quanto um construtor parametrizado, você permite que objetos inicializados e não inicializado sejam criados. Sobrecarga de Operadores Sobrecarga de Operadores Sobrecarregar um operador significa redefinir o seu símbolo, de maneira que ele se aplique também a tipos de dados definidos pelo usuário como estruturas e classes. A sobrecarga transforma expressões obscuras e complexas em outras mais claras e intuitivas. Por exemplo: Total = soma(A, B); pode ser trocada por: Total = A + B; Quando um operador é sobrecarregado, nenhuma parte de seu significado original é perdida. O fato é que uma nova operação relativa à classe específica é definida. Leka Highlight Exemplos de Aplicações Uma classe que define uma lista linkada pode usar o operador “+” para adicionar um objeto à lista. Uma classe que implementa uma pilha pode usar o operador “+” para colocar um objeto na pilha. Limitações da Sobrecarga de Operadores (1) • É necessário respeitar a definição original do operador. Por exemplo, não é possível mudar um operador binário para criar um operador unário. • O programador deve limitar-se aos operadores existentes. Não é permitido estender a linguagem inventando novos operadores como, por exemplo: =#. • O operador sobrecarregado não pode alterar as regras de precedência e associatividade do operador original. Por exemplo, o operador de multiplicação (*) tem precedência sobre o de adição (+) e isto não pode ser modificado por meio de sobrecargas. Limitações da Sobrecarga de Operadores (2) • Nem todos os operadores podem ser sobrecarregados. Por exemplo, não podem ser sobrecarregados: o operador ponto de acesso a membros(.), o operador de resolução de escopo (::), o operador condicional ternário(?) e o símbolo de diretivas de pré-processamento (#). • Pelo menos um dos parâmetros da função operadora deve ser objeto da classe. Isto significa que não podemos redefinir as operações para os tipos da linguagem. Limitações da Sobrecarga de Operadores (3) • Não se pode combinar sobrecargas para gerar uma terceira função operadora. Por exemplo, o fato de termos sobrecarregado os operadores de multiplicação (+) e de atribuição (=) não atribui à classe o operador += (ele deve ser definido explicitamente). • Os operadores =, -> e () só podem ser sobrecarregados com função operadora membro de classe (não como friend). • As funções de operador não podem ter argumento default. Sobrecarregando um Operador Tipo de operador Implementação Número de parâmetros Unário Função-membro 0 Unário Função amiga 1 Binário Função-membro 1 Binário Função amiga 2 Sintaxe da Sobrecarga Sintaxe – Sobrecarga Função-membro tipo-retorno operator símbolo-operador(); tipo-retorno nome-classe :: operator símbolo-operador() Função amiga friend tipo-retorno operator símbolo-operador(); Sobrecarga de Operadores Unários Os operadores unários operam sobre um único operando. São exemplos de operadores unários: incremento(++), decremento(--), menos unário(-) e !(negação). Exemplo A operação é realizada no objeto que gera a chamada para a função, através do ponteiro THIS passado implicitamente. Função Chamada à função Equivale a void operator ++() {++x; ++y;} ++p1; p1.operator++(); Sobrecarga de Operadores Binários Os operadores binários operam sobre dois operandos. São exemplos de operadores binários: + , - , * , / , >, ==, etc. Quando sobrecarregamos operadores binários, a função operadora tem um argumento. A função operadora de um operador binário é membro do objeto escrito à esquerda do operador e recebe como argumento o objeto escrito à direita do operador. Exemplo venda venda :: operator + (venda v) { int pec = npecas+ v.npecas; float pre = preco + v.preco; return venda (pec, pre); } Função Chamada à função Equivale a venda operator + (venda v) ; T = A + B; T = A.operator + (B); Função Operadora com Número Inteiro Não podemos escrever instruções como: p3 = 5 + p1; pois não temos o equivalente p3 = 5.operator + (p1) já que número inteiro não tem funções- membro. Para expressões nas quais uma variável de um tipo básico seja o primeiro operando, devemos usar funções amigas. Função Chamada à função Equivale a ponto operator + (int n) {return ponto (x+n, y+n);} p3 = p1 + 5; p3 = p1.operator + (5); Funções Amigas na Sobrecarga de Operadores Na sobrecarga de operadores as funções amigas permitem o uso de expressões nas quais o operador da esquerda é de um tipo básico, uma constante ou um objeto de uma classe diferente da qual o operador é membro. Para isso, a função operadora deve ser declarada como amiga e ter dois argumentos Ex: friend operator +(int n, ponto p); Nesse caso, p3 = 5 + p1; é interpretada como p3 = operator+ (5, p1); Observação Uma função operadora amiga deve receber no mínimo um argumento objeto. Então, você não pode criar uma função operadora binária como operator+() que receba dois inteiros como argumentos. Esta restrição previne a redefinição de operadores internos da linguagem. Retornando um Objeto da Função Operadora 1. Criar um objeto temporário a ser retornado. 2. Retornar um objeto temporário sem nome. 3. Retornar o próprio objeto usando o ponteiro THIS. Criar um Objeto Temporário a ser Retornado classe ponto { public: ponto (int x1=0, int y1=0) {x=x1; y=y1;} // construtor ponto operator ++() // função operadora pré-fixada { ++x; ++y; ponto temp; temp.x = x; temp.y = y; return temp; } }; Retornar um Objeto Temporário sem Nome (1) Um objeto temporário sem nome é criado usando-se o nome de sua classe, seguido de parênteses contendo os argumentos do construtor (inicializadores) separados por vírgula. Ele só existe no instante em que for retornado. Retornar um Objeto Temporário sem Nome (2) classe ponto { public: ponto (int x1=0, int y1=0) {x=x1; y=y1;} // construtor ponto operator ++() // função operadora pré-fixada { ++x; ++y; return ponto (x,y); } }; Retornar o próprio objeto usando o ponteiro THIS Podemos retornar o próprio objeto usando o ponteiro THIS: Exemplo: return *this;
Compartilhar