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)? |
|
Rashmistrz |
» 2017-01-03 00:53:42 To o czym mówisz zachodzi. #include <iostream> int main() { int a, b; ( a = b = 1 ) ++; std::cout << a << ' ' << b; } Też chciałbym to wiedzieć... |
|
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 |
|
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 :-) ? |
|
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? |
|
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. |
|
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 #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(); }
|
|
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. |
|
« 1 » 2 |