Visualizzazione dei risultati da 1 a 5 su 5
  1. #1

    [C++] Overload operatori strano

    Ho scritto questo codice per fare un po' di pratica con gli operatori, ed ho scoperto una cosa strana:

    codice:
    #include <iostream>
    
    using namespace std;
    
    class Zn
    {
        private:
            unsigned int _n;
            int _val;
            int _mod(int x);
        public:
            Zn(unsigned int n){ _n = n; }
    
            Zn operator =(Zn b);
            Zn operator =(int x);
            Zn operator +(Zn b);
            //Zn operator -(Zn b;)
    
            void print(){ cout << _val<< "\n" ; }
    };
    
    int Zn::_mod(int x)
    {
        if (x < 0)
            return _n - ((-x) % _n);
        else
            return x % _n;
    }
    
    Zn Zn::operator =(Zn b)
    {
        cout << "Chiamato Zn = Zn\n";
        _val = _mod(b._val);
        return *this;
    }
    
    Zn Zn::operator =(int x)
    {
        cout << "Chiamato Zn = Int\n";
        _val = _mod(x);
        return *this;
    }
    
    Zn Zn::operator +(Zn b)
    {
        cout << "Chiamato Zn + Zn\n";
        Zn temp(_n);
        temp = _mod(_val + b._val);
        return temp;
    }
    
    int main()
    {
        Zn a(5), b(5), c(5);
    
        a = 2; cout << "STOP 1!\n";
        c = a + 4; cout << "STOP 2!\n";
        a.print(); c.print();
    
        return 0;
    }
    lo compila correttamente e funziona anche.

    Ora, io ho ridefinito l' = tra classe e classe, e tra classe e int, e il + tra classe e classe.
    Nel main vado a fare con c = a + 4, classe + int, ma classe + int non è definita! Come fa a "indovinare" cosa deve fare?!?!?!!?

  2. #2
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    Ciao ... La cosa è abbastanza semplice ... Quando in una classe viene definito un costruttore che prende un solo parametro, si crea automaticamente anche una conversione "automatica" tra il tipo del parametro e la classe ad esempio:
    codice:
    #include<iostream>
    using namespace std;
    class A
    {
    public:
    	A( int int_par ) : a(int_par){}
    	int a;
    	A operator+ ( const A& right ) const
    	{
    		cout << "Richiamato A + A" << endl;
    		return A(a + right.a);
    		// oppure "return a+right.a;"
    	}
    };
    
    int main()
    {
    A ob1(1), ob2(2);
    cout << "** Somma A + A" << endl;
    A obSum = ob1 + ob2;
    cout << "** Somma A + int" << endl;
    obSum = obSum + 4;
    cout << "obSum = " << obSum.a << endl;
    return 0;
    }
    Questo codice funzionante (almeno spero) è simile al tuo ... Se guardi la 5a linea del codice nel main, puoi vedere lo stesso comportamento che ti ha incuriosito (anche nella parte commentata della definizione dell' operatore overloaded) ... Questo perchè (come già detto) si viene a creare una conversione automatica (ove bisogno e a meno che non definita) tra il tipo del parametro (int in questo caso) e il tipo della classe (A) ..Insomma viene richiamato "di nascosto" il costruttore di A con il parametro int (4) per creare un' oggetto temporaneo il quale viene utilizzato come argomento per l' operatore + ... Spero di averti illuminato e non confuso di più ...
    C++ 4ever
    496e2062696e6172696f206e6f6e2063692061767265737469 206e656d6d656e6f2020726f7661746f203a29

  3. #3
    Perfetto grazie tutto chiaro, solo 2 domande:
    1) Però perché "int + class" non lo sa fare (invece di "class + int") ?
    2) Facendo questa chiamata nascosta, non si spreca memoria?

    Anzi già che ci sto ti chiedo un'altra cosa sugli operatori che mi fa preoccupare:

    Leggendo un libro sul c++, ho letto di fare molta attenzione riguardo al costruttore per copia, perché visto che quello di default copia bit a bit, se uso puntatori nella classe rischio di andare a condividere lo stesso membro tra più classi se uso l'=. Questo fatto mi ha fatto venire la paranoia e non so mai bene cosa fare per fare le cose fatte bene...

    Ad esempio se ho la classe C, e C1, C2, C3 tre variabili di quella classe, se io scrivo:
    C3 = C1 + C2
    allora, viene chiamato il + di C1 e viene passato C2, il + fa il suo lavoro e crea un NUOVO oggetto che chiamiamo T1; Poi viene chiamato il costruttore per copia (o l'operator = ?!?) di C3, gli viene passato T1, e si crea un nuovo oggetto T2, e T1 muore. Infine T2 viene copiato bit a bit in C3, e T2 muore.

    Ora, non sono per niente sicuro di quello che ho detto (perdonami sto studiando ora), ma chi viene chiamato in quel codice? il costruttore per copia o l'=?
    E inoltre possibile che per una semplice assegnazione vengono create ben 2 classi temporanee? Non è uno spreco indecente di memoria? Se facessi qualche espressione composita tipo (C1 + C2) + (C3 + C4) vengono create tantissime variabili temporanee?!

    Inoltre c'è differenza tra fare:
    C C1; C C2; C C3; C3 = C1 + C2;
    e
    C C1; C C2; C C3 = C1 + C2;
    ??? quegli uguali che fanno???


    Scusami per le troppe domande, ma sono molto confuso su questa cosa!
    Ti ringrazio in anticipo

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    E inoltre possibile che per una semplice assegnazione vengono create ben 2 classi temporanee? Non è uno spreco indecente di memoria? Se facessi qualche espressione composita tipo (C1 + C2) + (C3 + C4) vengono create tantissime variabili temporanee?!
    Si. E appunto per evitare questo spreco che in C++0x è stata introdotta la "move semantics".

    Inoltre c'è differenza tra fare:
    C C1; C C2; C C3; C3 = C1 + C2;
    e
    C C1; C C2; C C3 = C1 + C2;
    ??? quegli uguali che fanno???
    nel primo caso è invocato operator=, nel secondo il costruttore di copia.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    1) Però perché "int + class" non lo sa fare (invece di "class + int") ?
    In linea generale il compilatore cerca sempre di convertire il secondo parametro con il tipo del primo ... Siccome la conversione da int a class è definita (seppur in maniera automatica) in fase di compilazione non si hanno errori di sorta, diversamente dal secondo caso (la cui conversione non avviene in automatico ma deve essere definita dal programmatore)
    Leggendo un libro sul c++, ho letto di fare molta attenzione riguardo al costruttore per copia, perché visto che quello di default copia bit a bit, se uso puntatori nella classe rischio di andare a condividere lo stesso membro tra più classi se uso l'=. Questo fatto mi ha fatto venire la paranoia e non so mai bene cosa fare per fare le cose fatte bene...
    In generale non bisogna mai lasciare il costruttore di copia di default quando si hanno puntatori come attributi (anche se delle volte potrebbe essere voluto) soprattutto quando si utilizzano i puntatori per allocare memoria
    Ad esempio se ho la classe C, e C1, C2, C3 tre variabili di quella classe, se io scrivo: C3 = C1 + C2 allora, viene chiamato il + di C1 e viene passato C2, il + fa il suo lavoro e crea un NUOVO oggetto che chiamiamo T1; Poi viene chiamato il costruttore per copia (o l'operator = ?!?) di C3, gli viene passato T1, e si crea un nuovo oggetto T2, e T1 muore. Infine T2 viene copiato bit a bit in C3, e T2 muore.
    In realtà verrebbe creato un oggetto temporaneo (T1) che poi verrebbe passato all' operator= per riferimento (quindi niente T2) e poi T1 verrebbe distrutto
    Ora, non sono per niente sicuro di quello che ho detto (perdonami sto studiando ora), ma chi viene chiamato in quel codice? il costruttore per copia o l'=?
    All' inizio è molto facile confondersi ... Comunque tieni bene a mente che quando un oggetto viene definito (quindi costruito) e copiato allo stesso tempo, viene richiamato il costruttore di copia (non a caso è chiamato costruttore). Se invece un oggetto viene copiato ma dopo la sua definizione, viene richiamato l' operator=
    C++ 4ever
    496e2062696e6172696f206e6f6e2063692061767265737469 206e656d6d656e6f2020726f7661746f203a29

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.