Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Dlaczego rezulatat operatora przypisania '=' jest referencją?

Ostatnio zmodyfikowano 2017-01-03 19:19
Autor Wiadomość
latajacaryba
Temat założony przez niniejszego użytkownika
Dlaczego rezulatat operatora przypisania '=' jest referencją?
» 2017-01-03 00:13:10
Pytanie jak w temacie. Oczywiście rezultatu być nie musi (void), ale żeby zrobić coś takiego:
K ob1, ob2, ob3;
ob1 = ob2 = ob3;
operator = musi zwracać K&. Dlaczego tak, a nie przez wartość? Czym to się różni (oprócz tego, że jak się domyślam nie wystąpi konstruktor kopiujący)?
P-155859
Rashmistrz
» 2017-01-03 00:53:42
To o czym mówisz zachodzi.
C/C++
#include <iostream>
int main() {
    int a, b;
    ( a = b = 1 ) ++; // wypisze 2 i 1
    std::cout << a << ' ' << b;
}
Też chciałbym to wiedzieć...
P-155862
latajacaryba
Temat założony przez niniejszego użytkownika
» 2017-01-03 01:05:22
Może napisze cały przykład z ksiazki J Grębosza:
Class K
K & operator=(K & wzor);
Dlaczego wynik jest REFERENCJĄ do obiektu a nie obiektem?
I dlaczego przekazujemy przez referencję argument?
Przyklad str 806 na samym dole strony jest definicja
P-155864
mokrowski
» 2017-01-03 02:11:10
Wyobraź sobie że referencja jest zakamuflowanym wskaźnikiem który ma "normalne techniki przypisania" (proszę nie czepiaj się słowa normalne inaczej ... proste). To jest takie że nie trzeba stosować * (gwiazdki) lub & (ampersand'a). Dodatkowo referencja nie może wskazać na adres pusty (w przeciwieństwie do wskaźnika) (Niech nikt nie wyskakuje ze sztuczką że można... to tylko namiesza w głowie @rybie).

Jak już to przemyślisz i przyjmiesz (choćby teraz "na wiarę") to zauważysz że referencja wskazuje zawsze na jakiś obiekt i _nie_może_ wskazać na bzdurne adresy...

Jeśli chcesz przypisaniem wykonywać "pociągi" jakie opisałeś ( a = b = c = 1), to każdy z elementów powinien zwrócić referencję czyli w uproszczeniu (dużym) "bezpieczne wskazanie" na obiekt. Gdyby operator= zwracał kopię, to przypisanie było by wykonane do kopii a później... była by ona niszczona bo kompilator orientował by się że nie jest potrzebna. Tu tego nie chcemy.

Zwrócenie wartości w operatorze operator= , na końcu to najczęściej: return *this; czyli... "bezpieczne wskazanie na siebie". A dlaczego * przed this? Bo zwracana jest referencja a ona ma taką składnię która potrzebuje _obiektu_ a nie wskaźnika (this jest przecież wskaźnikiem a więc wymaga wyłuskania * ).

Kiedy jest zwracana kopia z operatorów? Ano np. wtedy gdy potrzebujemy innej wartości. Np. operator post-inkrementacji który ma sygnaturę: TypKlasy operator++(int) { ... }
Jak widać ma kopię bo należy w {...} _stworzyć_ nową instancję obiektu z zachowaną kopią oryginalnego (this), inkrementować zawartość oryginalnego this i zwrócić tworzoną w {...} kopię. To powinna być kopia bo jak w {...} zrobisz obiekt na stosie (bez new), to zakończenie funkcji operatora zniszczy obiekt. Zwrócenie wskaźnika lub referencji (która przecież jest "bezpiecznym wskaźnikiem") będzie niebezpieczne i _niestety_ często działa choć kompilator wyraźnie ostrzega że robisz "kuku" :-)

Zrobię może jakiś prosty licznik abyś zrozumiał. W ramach ćwiczenia, dodaj sobie operatory pre/post dekrementacji i operator wyprowadzenia na strumień :-)

#include <iostream>

// Prosty licznik który po przekroczeniu max, zapętla się od min..
class Counter {
public:
    // Konstruktory: bezargumentowy, 1 argumentowy i 2 argumentowy
    Counter(unsigned min_value = 0, unsigned max_value = 10)
        : min_value{min_value}, max_value{max_value}, value{min_value} {}
    // Konstruktor kopiujący
    Counter(const Counter& src)
        : min_value{src.min_value}, max_value{src.max_value}, value{src.value} {}
    // Operator przypisania zwracający ref. na siebie samego...
    Counter& operator=(const Counter& src) {
        min_value = src.min_value;
        max_value = src.max_value;
        return *this;
    }
    // Operator preinkrementacji który "inkrementuje siebie i siebie zwraca"
    Counter& operator++() {
        ++value;
        if(value > max_value) {
            value = min_value;
        }
        return *this;
    }
    // Operator postinkrementacji który "robi swoją kopię, inkrementuje siebie i zwraca kopię
    // która zawiera stary licznik"
    Counter operator++(int) {
        // Tu wykonam kopię "siebie"
        Counter prev_counter(*this);
        ++(*this); // Tu zadziała operator++()
        // Równie dobrze można napisać:
        // this->operator++();
        // lub..
        // ++value;

        // Zwrot kopii.
        return prev_counter;
    }
    // Nie będę mieszał, zrobię proste get()
    unsigned get() const {
        return value;
    }
private:
    unsigned min_value;
    unsigned max_value;
    unsigned value;
};

int main() {
    using namespace std;
    Counter c = Counter(5, 7);
    // Testy... jawnie łamane DRY..
    cout << c.get() << endl;
    ++c;
    cout << c.get() << endl;
    ++c;
    cout << c.get() << endl;
    c++;
    cout << c.get() << endl;
}

PS. To chyba o czymś świadczy że coraz więcej ludzi otacza kod log'iem a nie cpp :-/ ? Może by ruszyć d*psko i poprawić formater :-) ?
P-155865
latajacaryba
Temat założony przez niniejszego użytkownika
» 2017-01-03 11:27:27
Gdyby operator= zwracał kopię, to przypisanie było by wykonane do kopii a później... była by ona niszczona bo kompilator orientował by się że nie jest potrzebna.
Przeciez zwracamy kopie, a ta kopia jest przypisywana do obiketu na rzecz ktorego wywolalismy = przyklad
K a, b, c;
A = b = c;
Do b jest przypisywana kopia. Wiec w czym jest problem?
P-155868
pekfos
» 2017-01-03 11:33:52
Obiekt, zwrócony przez funkcję przez wartość, jest tymczasowy. Modyfikowanie go nie ma większego sensu. Operatory, kiedy tylko mogą, zwracają referencje, żeby uniknąć zbędnego kopiowania, które może być bardzo kosztowne, lub nawet niemożliwe.

To chyba o czymś świadczy że coraz więcej ludzi otacza kod log'iem a nie cpp :-/ ? Może by ruszyć d*psko i poprawić formater :-) ?
Świadczy na przykład o tym, że ludzie nie potrafią czytać do końca i myślą, że [code] wystarczy :P Jak masz jakieś celniejsze uwagi, niż 'popraw', to załóż temat w odpowiednim dziale.
P-155869
mateczek
» 2017-01-03 11:51:09
Gdyby operator= zwracał kopię, to przypisanie było by wykonane do kopii a później... była by ona niszczona bo kompilator orientował by się że nie jest potrzebna.
a kto ci broni
C/C++
#include<iostream>
using namespace std;
class mInt {
    int skladnik;
public:
    mInt( int val ) {
        skladnik = val;
    }
    mInt operator =( mInt temp ) {
        skladnik = temp.skladnik;
        return * this;
    }
    void wyswietl() {
        cout << skladnik << endl;
    }
   
};
int main()
{
    mInt A( 1 ), B( 2 ), C( 3 );
    A.wyswietl();
    B.wyswietl();
    C.wyswietl();
   
    A = B = C;
    A.wyswietl();
    B.wyswietl();
}
P-155870
mokrowski
» 2017-01-03 12:26:21
Spoko @pefkos mam celniejsze uwagi jak widzisz po aktywności. A formater wymaga poprawy i wiesz to Ty i wiem Ja. EOT.
P-155871
« 1 » 2
  Strona 1 z 2 Następna strona