Προς το περιεχόμενο

C++ references provlima (?)


Turrican

Προτεινόμενες αναρτήσεις

Δημοσ.

Έχω μια απορία για το πως δουλεύουν ακριβώς οι 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, ενώ την δεύτερη έμεινε ανέπαφο. Γιατί συμβαίνει αυτό και πιο από τα δύο είναι το σωστό;

Δημοσ.

Δεν σε κατάλαβα ομως πια η διαφορά αν η reference είναι A ή B στην αλλαγή και πως γίνεται αυτή; -δεν φαίνεται να καλείται ο copy constructor το δοκίμασα- Εξάλου τα instances είναι B που είναι και A.

 

Σκέψου οτι η το A είναι interface List και το B είναι implementation LinkedList : List. Σκέψου επίσης οτι τα b1 και b2 γίνονται allocate στο heap (με new).

 

Αν έχω την reference ως LinkedList συμβαίνουν άσχημα πράγματα και προσπαθώ να καταλάβω γιατί...

Δημοσ.

Δεν κατάλαβα ακριβώς τι προσπαθείς να κάνεις, αλλά διαφωνώ με τον τρόπο που χρησιμοποιείς τον πολυμορφισμό της 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

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; )

 

Δηλαδή αυτο που με ενδιαφέρει, ειναι να καταλάβω το μηχανισμό λειτουργίας των αναφορών...

Δημοσ.

Επίσης:

 

όταν δίνεις Α& 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 δοκίμασα να τον βάλω και είδα οτι δεν καλείται.

 

Αυτά και ευχαριστώ για τις απαντήσεις.

Δημοσ.

Όπως σου είπα και πριν τα έχεις μπερδέψει τα πραγματα:

-Τα 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 σε συναρτήσεις. Δηλαδή είναι καθαρά καλοπιστικό στοιχείο του κώδικα.

Δημοσ.

Με βάση τα παραπάνω που σου είπα είναι προφανές ότι είναι λάθος που προσπαθείς να βάλεις νέα τιμη 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

2. Το 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 :)

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...