FONDAMENTI DI INFORMATICA II Ingegneria Gestionale a a

  • Slides: 28
Download presentation
FONDAMENTI DI INFORMATICA II Ingegneria Gestionale a. a. 2001 -2002 - 4° Ciclo Overloading

FONDAMENTI DI INFORMATICA II Ingegneria Gestionale a. a. 2001 -2002 - 4° Ciclo Overloading degli Operatori 1

Overloading degli Operatori Definizione: L’overloading degli operatori serve a definire, per mezzo degli operatori

Overloading degli Operatori Definizione: L’overloading degli operatori serve a definire, per mezzo degli operatori tradizionali, le operazioni che coinvolgono i dati dei tipi nuovi definiti dall’utente. Gli operatori utilizzabili sono cioè quelli già definiti come tali nel C++ e la ridefinizione delle operazioni che essi potranno eseguire non influirà sulla loro: • precedenza, • associatività, • e numero di operandi. Metodo per l’overloading L’overloading di un operatore si ottiene definendo una funzione con il nome composto dalla parola riservata operator seguita dall’operatore da ridefinire (ad es. : operator+, operator*, . . ecc. ) 2

Overloading degli Operatori Ridefinibilità degli operatori: Tutti gli operatori possono essere ridefiniti, tranne i

Overloading degli Operatori Ridefinibilità degli operatori: Tutti gli operatori possono essere ridefiniti, tranne i seguenti: . . * : : ? : sizeof Tipologia delle funzioni di overloading degli operatori: Le funzioni di overloading degli operatori: • devono essere funzioni membro di una classe per tutti gli operatori di assegnazione e per gli operatori: ( ) [ ] -> • devono essere funzioni non membro (da dichiarare se possibile friend, per migliorarne l’efficienza) quando si ridefiniscono con cout e cin gli operatori: << >> • possono essere sia funzioni membro che non membro (da dichiarare se possibile friend, per migliorarne l’efficienza) per tutti gli altri operatori. 3

Overloading degli Operatori Nota: E’ bene tener presente che nel caso di funzione di

Overloading degli Operatori Nota: E’ bene tener presente che nel caso di funzione di overloading di operatore, definita come funzione membro, essa non può essere dichiarata static. Operatività dell’overloading degli operatori: Un operatore ridefinito per gli oggetti di una determinata classe viene richiamato quando: • nel caso di operatore binario, l’operando sinistro è un oggetto della classe, oppure: • nel caso di operatore unario, l’unico operando è un oggetto della classe. 4

Overloading degli Operatori Overloading di operatori binari con funzioni membro: La funzione di ridefinizione

Overloading degli Operatori Overloading di operatori binari con funzioni membro: La funzione di ridefinizione dell’operatore assume la forma: Prototipo: Tipo_Restituito operator Segno_Operatore (Tipo_Argomento); Implementazione: Tipo_Restituito operator Segno_Operatore (Tipo_Argomento Variabile_Argomento) {……codice della funzione. . . …} La suddetta implementazione viene invocata quando in una espressione: …. Variabile 1 Segno_Operatore Variabile 2 …. la Variabile 1 (almeno) è un oggetto della classe e, in tal caso, l’invocazione assume la forma: …… Variabile 1. operator Segno_Operatore (Variabile 2)…. . 5

Overloading degli Operatori Overloading di operatori binari con funzioni membro: Nell’ambito del codice della

Overloading degli Operatori Overloading di operatori binari con funzioni membro: Nell’ambito del codice della funzione membro di nome: “operator. Segno_Operatore” si ha l’accesso immediato a tutti i dati membro pubblici e privati relativi all’oggetto Variabile 1 (che è l’oggetto per cui viene invocata la funzione), mentre gli stessi dati sono accedibili per l’oggetto Variabile 2 selezionandoli con il nome dell’oggetto stesso (ossia con: Variabile 2. Nome_dato) Mediante i suddetti accessi ai dati membro degli oggetti Variabile 1 e Variabile 2 è possibile ridefinire il Segno_Operatore facendogli fare una operazione diversa da quella originale, e restituendo, poi, una variabile del tipo indicato nel prototipo. 6

Overloading degli Operatori Esempio di overloading di operatori binari con funzioni membro: #include <iostream.

Overloading degli Operatori Esempio di overloading di operatori binari con funzioni membro: #include <iostream. h> class Cmplex { public: Cmplex (int, int); Cmplex operator+ (Cmplex); Cmplex operator= (Cmplex); int r, i; }; Cmplex: : Cmplex (int rea, int ima){ r= rea; i= ima; } 7

Overloading degli Operatori Cmplex: : operator+ (Cmplex c 2){ Cmplex csum (0, 0); csum.

Overloading degli Operatori Cmplex: : operator+ (Cmplex c 2){ Cmplex csum (0, 0); csum. r= r + c 2. r; csum. i= i + c 2. i; return csum; } Cmplex: : operator= (Cmplex d){ return Cmplex (d. r, d. i); } int main(){ Cmplex a(5, 5); Cmplex b(2, 2); Cmplex c(0, 0); c= a+b; cout<<c. r<<"+i"<<c. i<<endl; return 0; } 8

Overloading degli Operatori Overloading di operatori binari con funzioni non membro: La funzione di

Overloading degli Operatori Overloading di operatori binari con funzioni non membro: La funzione di ridefinizione dell’operatore assume la forma: Prototipo: Tipo_Restituito operator Segno_Operatore (Tipo_Argomento, Tipo_Argomento); Implementazione: Tipo_Restituito operator Segno_Operatore (Tipo_Argomento 1 Variabile_Argomento 1, Tipo_Argomento 2 Variabile_Argomento 2 ) {……codice della funzione. . . …} La suddetta implementazione viene invocata quando in una espressione: …. Variabile 1 Segno_Operatore Variabile 2 …. la Variabile 1 (almeno) è un oggetto della classe e, in tal caso, l’invocazione assume la forma: …… operator Segno_Operatore (Variabile 1, Variabile 2)…. . 9

Overloading degli Operatori Overloading di operatori binari con funzioni non membro: Nell’ambito del codice

Overloading degli Operatori Overloading di operatori binari con funzioni non membro: Nell’ambito del codice della funzione non membro di nome: “operator. Segno_Operatore” si ha l’accesso a tutti i dati membro pubblici (e anche privati, se la funzione è stata definita friend) relativi agli oggetti Variabile 1 e Variabile 2, selezionandoli con il nome degli oggetti stessi (ossia con: Variabile 1. Nome_dato, Variabile 2. Nome_dato). Mediante i suddetti accessi ai dati membro degli oggetti Variabile 1 e Variabile 2 è possibile ridefinire il Segno_Operatore facendogli fare una operazione diversa da quella originale, e restituendo, poi, una variabile del tipo indicato nel prototipo. 10

Overloading degli Operatori Esempio di overloading di operatori binari con funzioni non membro: #include

Overloading degli Operatori Esempio di overloading di operatori binari con funzioni non membro: #include <iostream. h> class Complesso { friend Complesso operator+ (Complesso, Complesso); public: Complesso (int=0, int=0); Complesso operator= (Complesso); int get. Real ( ) {return r; } int get. Imagin ( ) {return i; } private: int r, i; }; Complesso: : Complesso (int a, int b){ r= a; i= b; } 11

Overloading degli Operatori Complesso operator+ (Complesso ca, Complesso cb){ int re= ca. r +

Overloading degli Operatori Complesso operator+ (Complesso ca, Complesso cb){ int re= ca. r + cb. r; int im= ca. i + cb. i; return Complesso (re, im); } Complesso: : operator= (Complesso cm){ return Complesso (cm. r, cm. i); } int main ( ){ Complesso c 1(4, 5); Complesso c 2(6, 7); Complesso c 3= c 1 + c 2; cout << c 3. get. Real( ) << "+i" << c 3. get. Imagin ( ) <<"n"; return 0; } 12

Overloading degli Operatori Overloading di operatori unari con funzioni membro: La funzione di ridefinizione

Overloading degli Operatori Overloading di operatori unari con funzioni membro: La funzione di ridefinizione dell’operatore assume la forma: Prototipo: Tipo_Restituito operator. Segno_Operatore ( ); Implementazione: Tipo_Restituito operator. Segno_Operatore ( ) {……codice della funzione. . . …} La suddetta implementazione viene invocata quando in una espressione: …. Segno_Operatore Variabile …. la Variabile è un oggetto della classe e, in tal caso, l’invocazione assume la forma: …… Variabile. operator. Segno_Operatore ( )…. . 13

Overloading degli Operatori Overloading di operatori unari con funzioni membro: Nell’ambito del codice della

Overloading degli Operatori Overloading di operatori unari con funzioni membro: Nell’ambito del codice della funzione membro di nome: “operator. Segno_Operatore” si ha l’accesso immediato a tutti i dati membro pubblici e privati relativi all’oggetto Variabile (che è l’oggetto per cui viene invocata la funzione). Mediante i suddetti accessi ai dati membro dell’oggetto Variabile è possibile ridefinire il Segno_Operatore facendogli fare una operazione diversa da quella originale, e restituendo, poi, una variabile del tipo indicato nel prototipo. 14

Overloading degli Operatori Esempio di overloading di operatori unari con funzioni membro: #include <iostream.

Overloading degli Operatori Esempio di overloading di operatori unari con funzioni membro: #include <iostream. h> class Angle{ public: Angle (int=0); Angle operator* ( ); int get( ); private: int arc; }; Angle: : Angle (int a) {arc= a; } 15

Overloading degli Operatori Angle: : operator* ( ){ arc= -360 + (arc % 360);

Overloading degli Operatori Angle: : operator* ( ){ arc= -360 + (arc % 360); return Angle(arc); } int Angle: : get( ){ return arc; } int main ( ){ Angle arco(50); arco= *arco ; cout << arco. get( ); return 0; } 16

Overloading degli Operatori Overloading di operatori unari con funzioni non membro: La funzione di

Overloading degli Operatori Overloading di operatori unari con funzioni non membro: La funzione di ridefinizione dell’operatore assume la forma: Prototipo: Tipo_Restituito operator. Segno_Operatore (Tipo_Argomento); Implementazione: Tipo_Restituito operator. Segno_Operatore (Tipo_Argomento Variabile_Argomento) {……codice della funzione. . . …} La suddetta implementazione viene invocata quando in una espressione: …. Segno_Operatore Variabile …. la Variabile è un oggetto della classe e, in tal caso, l’invocazione assume la forma: …… operator Segno_Operatore (Variabile)…. . 17

Overloading degli Operatori Overloading di operatori unari con funzioni non membro: Nell’ambito del codice

Overloading degli Operatori Overloading di operatori unari con funzioni non membro: Nell’ambito del codice della funzione non membro di nome: “operator. Segno_Operatore” si ha l’accesso a tutti i dati membro pubblici (e anche privati, se la funzione è stata definita friend) relativi all’oggetto Variabile, selezionandoli con il nome dell’oggetto stesso (ossia con: Variabile. Nome_dato). Mediante i suddetti accessi ai dati membro dell’oggetto Variabile è possibile ridefinire il Segno_Operatore facendogli fare una operazione diversa da quella originale, e restituendo, poi, una variabile del tipo indicato nel prototipo. 18

Overloading degli Operatori Esempio di overloading di operatori unari con funzioni non membro: #include

Overloading degli Operatori Esempio di overloading di operatori unari con funzioni non membro: #include <iostream. h> class Angle { public: Angle (int= 0); int get ( ); private: int arc; }; Angle: : Angle (int a) {arc= a; } int Angle: : get ( ) {return arc; } 19

Overloading degli Operatori Angle operator* (Angle val) {int compl= -360 + (val. get( )

Overloading degli Operatori Angle operator* (Angle val) {int compl= -360 + (val. get( ) % 360); return Angle (compl); } int main ( ) {Angle arco (60); arco= *arco; cout << arco. get( ); return 0; } 20

Overloading degli Operatori Conversione tra tipi diversi: Nel caso dei tipi predefiniti la conversione

Overloading degli Operatori Conversione tra tipi diversi: Nel caso dei tipi predefiniti la conversione di una variabile di un tipo ad una di tipo diverso si ottiene esplicitamente con l’operatore static_cast, nel modo seguente: ……. . static_cast <Tipo. B> (Variabile_Tipo. A) ……. questa espressione crea un oggetto temporaneo del Tipo. B a partire dalla Variabile_Tipo. A. Nel caso di tipi definiti dall’utente, la stessa cosa, ossia la conversione da un tipo definito dall’utente ad un tipo primitivo, o viceversa, oppure ad un tipo ancora definito dall’utente, può ottenersi con i costruttori di conversione, che ricevono un solo argomento e che convertono gli oggetti di altri tipi (inclusi i tipi predefiniti) in oggetti di una determinata classe. 21

Overloading degli Operatori Conversione tra tipi diversi con l’operatore di conversione: La conversione nel

Overloading degli Operatori Conversione tra tipi diversi con l’operatore di conversione: La conversione nel caso di tipi definiti dall’utente può anche ottenersi per mezzo di un opportuno operatore di conversione (o di cast), da costruire con una funzione membro non static, che deve essere realizzata e richiamata come indicato nel seguito. L’ operatore di conversione viene anche esso definito per mezzo della parola riservata operator che, questa volta, non viene utilizzata in connessione con un operatore da ridefinire, ma con un tipo (o oggetto) verso il quale si vuole definire una conversione. 22

Overloading degli Operatori Conversione tra tipi diversi con l’operatore di conversione: Prototipo: operator Tipo.

Overloading degli Operatori Conversione tra tipi diversi con l’operatore di conversione: Prototipo: operator Tipo. B ( ); Nota: non serve indicare che la funzione restituisce un oggetto di Tipo. B perché ciò è implicito nel fatto che la funzione, come sopra definita, converte un altro oggetto in un oggetto di Tipo. B Implementazione: Nome_Classe : : operator Tipo. B ( ) {…. implementazione della conversione…. …. . return Dato_Tipo. B; } Nota: il codice di implementazione della conversione opera sui dati membro pubblici e privati relativi all’oggetto per il quale la funzione operator Tipo. B viene invocata. Invocazione: …(Tipo. B) Oggetto_Tipo. A… che il compilatore traduce in: . . . Oggetto_Tipo. A. operator Tipo. B ( )…. 23

Overloading degli Operatori Esempio di conversione tra tipi diversi: #include<iostream. h> class Complesso {

Overloading degli Operatori Esempio di conversione tra tipi diversi: #include<iostream. h> class Complesso { public: Complesso (int, int); operator int ( ) ; private: int r, i; }; Complesso: : Complesso (int a, int b){ r= a; i= b; } Complesso: : operator int ( ) { return (i*i + r*r); } 24

Overloading degli Operatori int main ( ) { Complesso c(2, 3); int k= (int)

Overloading degli Operatori int main ( ) { Complesso c(2, 3); int k= (int) c; cout<<k<<"n"; return 0; } //Presenta 13. 25

Overloading degli Operatori L’overloading degli operatori ++ e - Gli operatori ++ e -

Overloading degli Operatori L’overloading degli operatori ++ e - Gli operatori ++ e - - operano come operatori di preincremento e predecremento nel caso che essi precedano la variable a cui si applicano. In questo caso il loro overloading non differisce da quello tradizionale degli operatori unari. Nel caso che essi seguano la variabile a cui si applicano essi invece operano come post incremento e post decremento e, quindi, la loro operatività va distinta da quella precedente. In questo secondo caso la distinzione si attua come indicato nelle pagine che seguono. 26

Overloading degli Operatori Nel caso di post incremento (ma lo stesso vale per il

Overloading degli Operatori Nel caso di post incremento (ma lo stesso vale per il post decremento), se l’overloading è implementato come funzione membro, quando s’incontra l’espressione: Variabile ++ il compilatore genera l’invocazione a funzione: Variabile. operator++ (0) il cui prototipo sarà: Tipo_Restituito operator++ (int); dove lo 0 è soltanto un valore fittizio necessario per distinguere il post incremento dal preincremento. 27

Overloading degli Operatori Nel caso di post incremento (ma lo stesso vale per il

Overloading degli Operatori Nel caso di post incremento (ma lo stesso vale per il post decremento), se l’overloading è implementato come funzione non membro, quando s’incontra l’espressione: Variabile ++ il compilatore genera l’invocazione a funzione: operator++ (Variabile, 0) il cui prototipo sarà: Tipo_Restituito operator++ (Tipo_Variabile, int); dove, anche in questo caso, lo 0 è soltanto un valore fittizio necessario per distinguere il post incremento dal preincremento. 28