380 likes | 683 Views
Overloading. Differenze nei vari linguaggi di Elisa Trifirò e Barbara Tacchino. Argomenti trattati. Overloading: un tipo di Polimorfismo Overloading in Java Overloading in C++ Overloading in C# Conclusioni. Classificazione di Cardelli-Wegner.
E N D
Overloading Differenze nei vari linguaggi di Elisa Trifirò e Barbara Tacchino
Argomenti trattati • Overloading: un tipo di Polimorfismo • Overloading in Java • Overloading in C++ • Overloading in C# • Conclusioni
Classificazione di Cardelli-Wegner • La classificazione più completa risale al 1985 ed è opera di Luca Cardelli e Peter Wegner:
Polimorfismo universale • Sono quelle funzioni che possono operare su più tipi purché vengano rispettate alcune proprietà. • Polimorfismo parametrico: programmazione generica. • Polimorfismo per inclusione: programmazione ad oggetti.
Polimorfismo parametrico • Idea: utilizzare un tipo come parametro in una funzione generica. • E’ il compilatore che genera di volta in volta l’implementazione corretta. • Esempio: template in C++
Polimorfismo per inclusione • Nell'approccio object-oriented si definisce la classe degli elementi su cui ha senso applicare una certa funzione. • Tutte le classi da essa derivate ne erediteranno le funzioni, con la possibilità di ridefinirle.
Polimorfismo ad-hoc • Nel polimorfismo ad-hoc rientrano: • Overloading • Coercion
Coercion • Coercion: quando un valore di un tipo viene visto (e talvolta trasformato) come valore di un altro tipo. • Esempio: nel sommare un float e un double, avviene una promozione da float a double.
Overloading • Il termine overloading (da to overload) significa sovraccaricamento e overloading delle funzioni indica la possibilità di attribuire allo stesso nome di funzione più significati. • Esempio: int x = 7 * 5; double y = 3.1 * 7.4;
Overloading in Java • In Java é ammesso l’overloading nel senso che é possibile definire più versioni di un metodo o costruttore che differiscono per la lista degli argomenti.
Esempio class MyComplex{ double a; double b; double m (MyComplex p){return p.a;} double m(double h){return this.a+h;} } Nota: non possono differire per il tipo di ritorno.
Esempio • In Java non é ammesso l’overloading di operatori. class MyComplex{ double a,b; public MyComplex add(MyComplex m){ this.a+=m.a; this.b+=m.b return new MyComplex(this.a,this.b);}}
Risoluzione dell’overloading in Java • La risoluzione dell’overloading é la scelta della versione da applicare ad ogni chiamata di metodo. • In Java é fatta staticamente ossia al momento della compilazione.
Algoritmo di risoluzione dell’overloading in Java • L’algoritmo di risoluzione é il seguente: • Si cercano tutte le versioni del metodo che potrebbero essere applicate, cioè con il nome giusto e con i tipi (statici) • Se si trovano più versioni applicabili, si elimina via via ogni versione meno “specifica” di un’altra • Se alla fine si arriva ad una sola versione, è quella da applicare, altrimenti si ha un errore statico
Considerazioni sulla risoluzione dell’overloading in Java • La risoluzione dell’overloading in Java corrisponde ad un preprocessing che sostituisce al nome del metodo un nome esteso con le opportune informazioni di tipo.
Un esempio errato public class B { public void unMetodo() { System.out.println(“Glup!”); } public int unMetodo() { System.out.println(“Glup!”); return 1; } } Questa classe dà errore in compilazione perché non vi possono essere due metodi con lo stesso nome e stessi parametri anche se con tipi di ritorno differenti.
Dynamic binding in Java • A run-time viene considerato il tipo dinamico del ricevitore della chiamata di metodo e da quello avviene la ricerca gerarchica del metodo da scegliere. • Non viene considerato il tipo dinamico dei parametri. • Si continua ad andare in alto nella gerarchia di classi finché non si arriva al primo applicabile esattamente al tipo dinamico.
Esempio class A { h(int i){return 0}; f(){return 1}; s(double d){return 2}; } class B extends A { f(){return 3}; h(int i){return 4}; s(int i){return 5};} class C extends A { f(){return 6}; } A a1=new B(); A a2=new C(); B b=new B(); A a=new A();
Esempio a.s(3.0); //2 a1.s(3.0); //2 b.s(0); //5 b.s(1.0); //2 ((A) a1).h(4); //4
Overloading in C++ • In C++ è permesso: • Due funzioni con lo stesso nome ma parametri e tipi di ritorno differenti: int media(int * array, int size); double media(double a,double b); • Due parametri passati per riferimento che differiscono per il qualificatore const sono considerati differenti: void f(int&); void f(const int&);
Esempio • In C++ e’ permesso l’overloading di operatori: class MyComplex{ double a,b; MyComplex operator +(const MyComplex &obj) { MyComplex temp; temp.a=(*this).a+obj.a; temp.b=(*this).b+obj.b; return temp; } };
Implementazione dell’overloading in C++ • Ad ogni funzione del programma il compilatore assegna un nome interno che dipende dal nome della funzione e dai suoi parametri. • Il meccanismo di risoluzione dipende dal compilatore.
Risoluzione dell’overloading in C++ • Si passa attraverso un processo di corrispondenza tra gli argomenti della chiamata e i parametri della funzione. • Il compilatore confronta gli argomenti della chiamata con le varie definizioni e se possibile ne invoca una.
Algoritmo di risoluzione dell’overloading in C++ • La risoluzione avviene in tre passi: • Identificazione delle funzioni candidate (funzioni che hanno lo stesso nome della funzione chiamata) • Scelta delle funzioni utilizzabili (funzioni i cui parametri corrispondono agli argomenti della chiamata per numero e tipo)
Algoritmo di risoluzione dell’overloading in C++ 2 • Scelta della migliore funzione utilizzabile ( funzione per cui gli argomenti corrispondono come tipi statici ai parametri)
Overloading in C# • Si possono dichiarare più metodi con lo stesso nome ma parametri diversi. • E’ permesso l’overloading di operatori. • E’ permesso l’overloading con tipi di ritorno diverso.
Esempio • class MyComplex { double a,b; public static operator + (MyComplex a,MyComplex q) { MyComplex z=new MyComplex((p.a+q.a),(p.b+q.b)); return z; }}
Overloading di operatori in C# • Gli operatori unari che possono essere overloaded in C# sono : + - ! ~ ++ -- true false • Gli operatori binari che possono essere overloaded sono : + - * / % & | ^ << >> == != > < >= <=
Risoluzione dell’overloading in C# • L’insieme delle funzioni candidate è ridotto a quelle funzioni applicabili rispetto alla lista degli argomenti. • Se questo insieme è vuoto si ha un errore in compilazione. • Altrimenti è scelta la migliore possibile.
Risoluzione dell’Overloading in C# • L’algoritmo di risoluzione è simile a quello utilizzato dal linguaggio Java.
Esempio class A{…} class B : A {…} class C : B {…} class D { public static void m(A a){…} public static void m(B b){…} public static void m(A a, B b){…} public static void m(B b, A a){…} }
Esempio (continuo) • A a=new A(); • C c=new C(); • D d=new D(); • d.m(a);/* D.m(A a) => d.m(A);*/ • d.m(c);/* D.m(A a), D.m(B b)=>d.m(B) • D.m(c,c);/*D.m(A a,B b), D.m(B b, A a) Error
Risoluzione degli operatori in C# • Le implementazioni degli operatori definite dall’utente hanno la precedenza su quelli predefiniti.
Overloading a run-time • A differenza di Java durante l’esecuzione, viene ignorato il tipo dinamico dell’oggetto che ha invocato il metodo e viene quindi applicato quello scelto a compile-time.
Linguaggio overloading consentito C++ costruttori, distruttori, funzioni, operatori (tutti compresi ',' , 'new', 'delete' e '->') conversioni implicite (cast) Java costruttori e funzioni C# costruttori, funzioni e operatori ad esclusione di: '.', =, &&, ||, ?, : new e tutti gli operatori di assegnazione composti come += *= perché vengono sempre eseguiti con l'espansione delle operazioni semplici (evitando i problemi in cui sia stato fatto l'overloading degli operatori semplici e non di quelli composti) conversioni implicite (cast)
Conclusioni • L’overloading, se usato correttamente, migliora la leggibilità del codice evitando nomi con ridondanza di informazioni.
Esempio • Volendo definire una funzione che calcoli la potenza di interi e un’atra per i float, potremmo chiamarle in due modi diversi (es.IPow e FPow). • Questo però nasconde la similarità della loro funzionalità.
Conclusioni • E’ difficile da gestire per il compilatore. • Il dynamic binding causa un rallentamento nell’esecuzione. • Il dynamic binding a run-time potrebbe dare errori non segnalati in compile-time.