Turrican Δημοσ. 21 Μαρτίου 2005 Δημοσ. 21 Μαρτίου 2005 Έχω μια απορία για το πως δουλεύουν ακριβώς οι references στην C++. Ιδού το παρακάτω πρόγραμμα (το έκανα πολύ απλό για να δούμε το πρόβλημα). > #include <iostream> class A { public: A() {} ~A() {} virtual char* getName() = 0; }; class B : public A { char* name; public: B(char* arg) : A(), name(arg) {} ~B() {} virtual char* getName() { return name; } }; int main (int argc, char* argv[]) { B b1("Ena"); // <--- Ftiaxno ena antikeimeno B std::cout << "b1, " << b1.getName() << ", " << &b1 << "\n"; B b2("Dyo"); // <--- Ftiaxnw akoma ena antikeimeno B std::cout << "b2, " << b2.getName() << ", " << &b2 << "\n"; B& rf = b1; // <--- Ftiaxnw reference kai tin orizw ws b1 std::cout << "rf, " << rf.getName() << ", " << &rf << "\n"; rf = b2; // <--- ??? Epitrepetai auto ??? std::cout << "rf, " << rf.getName() << ", " << &rf << "\n"; } Οταν το κάνω compile και το εκτελέσω βγάζει αυτό: b1, Ena, 0x22ff68 b2, Dyo, 0x22ff58 rf, Ena, 0x22ff68 rf, Dyo, 0x22ff68 Αν τώρα αλλάξω τον τύπο της reference στην γραμμή: B& rf = b1; σε: A& rf = b1; Ξανά compile, εκτέλεση και βγάζει αυτό: b1, Ena, 0x22ff68 b2, Dyo, 0x22ff58 rf, Ena, 0x22ff68 rf, Ena, 0x22ff68 Αν δείτε στην τελευταία γραμμή του output υπάρχει η διαφορά. Την πρώτη φορά το b1 μέσω της rf άλλαξε σε b2, ενώ την δεύτερη έμεινε ανέπαφο. Γιατί συμβαίνει αυτό και πιο από τα δύο είναι το σωστό;
kickeras Δημοσ. 22 Μαρτίου 2005 Δημοσ. 22 Μαρτίου 2005 sto ena kaneis reference ena B object kai sto allo ena A. De vlepw pouthena ston A() constructor na zitaei name. Epipleon den xreiazesai to virtual sto class B.
Turrican Δημοσ. 22 Μαρτίου 2005 Μέλος Δημοσ. 22 Μαρτίου 2005 Δεν σε κατάλαβα ομως πια η διαφορά αν η reference είναι A ή B στην αλλαγή και πως γίνεται αυτή; -δεν φαίνεται να καλείται ο copy constructor το δοκίμασα- Εξάλου τα instances είναι B που είναι και A. Σκέψου οτι η το A είναι interface List και το B είναι implementation LinkedList : List. Σκέψου επίσης οτι τα b1 και b2 γίνονται allocate στο heap (με new). Αν έχω την reference ως LinkedList συμβαίνουν άσχημα πράγματα και προσπαθώ να καταλάβω γιατί...
hayzel Δημοσ. 22 Μαρτίου 2005 Δημοσ. 22 Μαρτίου 2005 Δεν κατάλαβα ακριβώς τι προσπαθείς να κάνεις, αλλά διαφωνώ με τον τρόπο που χρησιμοποιείς τον πολυμορφισμό της C++. To σωστό κατά τη γνώμη μου, είναι να ορίσεις το reference σαν pointer: A* και να αποδώσεις τιμή την διεύθηνση των δύο αντικειμένων. A* rf = &b1; rf=&b2; για να πάρεις το όνομα του αντικειμένου δίνεις rf->getname() όταν δίνεις Α& rf=b1; στην πραγματικότητα κάνεις στατικό copy το object b1, και αφού δεν υπάρχει virtual copy στο αντικείμενο σου δεν αντιγράφεται με το rf=b2. Ο τρόπος που σου δίνω είναι πολύ πιο καθαρός από το να φτιάξεις copy method, γιατί η rf είναι ένας απλός pointer.
kickeras Δημοσ. 22 Μαρτίου 2005 Δημοσ. 22 Μαρτίου 2005 για να πάρεις το όνομα του αντικειμένου δίνεις rf->getname() swsta ksexasa na anaferw kai afto
Turrican Δημοσ. 22 Μαρτίου 2005 Μέλος Δημοσ. 22 Μαρτίου 2005 @kickeras 1. Στον constructor της A δεν ζητάει "name" γιατι υποτίθεται οτι είναι το interface ενώ η B το implementation. 2. Το virtual στην B δεν είναι απαραίτητο αλλά το σωστό έτσι είναι. Δες εδώ http://www.mozilla.org/hacking/portable-cpp.html#virtual_on_subclasses @hayzel Τι εννοεις static copy (bit copy?) και virtual copy (copy constructor?); Έχεις δίκιο σχετικά με τους δείκτες *αλλά* δεν είναι αυτό το θέμα. ------------- Το θέμα είναι: ------------- 1. Γιατί οταν η αναφορά είναι τύπου B ( B& rf = b1; ) το αντικείμενο που αναφέρει αλλάζει με την ( rf = b2; ) 2. Γιατί οταν η αναφορά είναι τύπου A ( A& rf = b1; ) το αντικείμενο που αναφέρει *δεν* αλλάζει με την ( rf = b2; ) Δηλαδή αυτο που με ενδιαφέρει, ειναι να καταλάβω το μηχανισμό λειτουργίας των αναφορών...
Turrican Δημοσ. 22 Μαρτίου 2005 Μέλος Δημοσ. 22 Μαρτίου 2005 Επίσης: όταν δίνεις Α& rf=b1; στην πραγματικότητα κάνεις στατικό copy το object b1, και αφού δεν υπάρχει virtual copy στο αντικείμενο σου δεν αντιγράφεται με το rf=b2. Ο τρόπος που σου δίνω είναι πολύ πιο καθαρός από το να φτιάξεις copy method, γιατί η rf είναι ένας απλός pointer. Δεν καταλαβαίνω τι εννοείς στατικό copy αλλά οι αναφορές από οσο ξέρω *είναι δείκτες* (under the covers...) οποτε η εντολή ( Α& rf = b1; ) πρέπει να είναι κάτι αντίστοιχο της ( A* const rf = &b1; ). Οσον αφορά το virtual copy, αν εννοείς τον copy constructor δοκίμασα να τον βάλω και είδα οτι δεν καλείται. Αυτά και ευχαριστώ για τις απαντήσεις.
hayzel Δημοσ. 22 Μαρτίου 2005 Δημοσ. 22 Μαρτίου 2005 Όπως σου είπα και πριν τα έχεις μπερδέψει τα πραγματα: -Τα references δεν είναι συνώνυμα με τα pointers. Απλά τα references είναι aliases σε pointers. Γιαυτό και σου είπα να χρησιμοποιήσεις pointers. Απόσπασμα απο το C++ Annotations v6.1.3: " Actually, references are implemented using pointers. So, references in C++ are just pointers, as far as the compiler is concerned. However, the programmer does not need to know or to bother about levels of indirection. Nevertheless, pointers and references should be distinguished: once initialized, references can never refer to another variable, whereas the values of pointer variables can be changed, which will result in the pointer variable pointing to another location in memory. " Oπότε τα references δηλώνονται στατικά κατά το compile και υπάρχουν ΜΟΝΟ και ΜΟΝΟ για να γίνεται πιο εύκολα το πέρασμα μεταβλητών by ref σε συναρτήσεις. Δηλαδή είναι καθαρά καλοπιστικό στοιχείο του κώδικα.
hayzel Δημοσ. 22 Μαρτίου 2005 Δημοσ. 22 Μαρτίου 2005 Με βάση τα παραπάνω που σου είπα είναι προφανές ότι είναι λάθος που προσπαθείς να βάλεις νέα τιμη b2 στον rf. Αυτό που μου κάνει εντύπωσει ότι ο g++ δεν μου βγάζει κανένα warning για την εντολή. βρήκα γιατί δεν βγάζει warning. Γιατί ο κώδικας σου κάνει το εξής: B b1("Ena"); // make b1 B b2("Dyo"); // make b2 A& rf=b1; // φτιάξε ένα some kind of alias for b1. To rf δείχνει στο b1 .... rf=b2; // το rf εξακολουθεί να είναι ένα pointer alias tou b1. Απλά αλλάζει την τιμή του. Οπότε το ισόδύναμο είναι σε ψευδοκώδικα b1=b2.
kickeras Δημοσ. 23 Μαρτίου 2005 Δημοσ. 23 Μαρτίου 2005 @kickeras2. Το virtual στην B δεν είναι απαραίτητο αλλά το σωστό έτσι είναι. Δες εδώ http://www.mozilla.org/hacking/portable-cpp.html#virtual_on_subclasses To da to link. Den eipa oti an to valeis einai lathos apla oti den to xreiazesai. Emas etsi mas to mathane kai to pio prosfato paradeigma pou eida itan sto source code tou vivliou tou Hill gia Raytracers pou to eixe xwris....anyway no harm done
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.