ntellos Δημοσ. 12 Ιανουαρίου 2012 Δημοσ. 12 Ιανουαρίου 2012 Έχω μία κλάση person την οποία κληρονομούν οι κλάσεις employees και patients. Τους employees και τους patients τους περνάω όλους σε ένα vector<person*> livings. Θέλω να περάσω το δείκτη livings[0] σε δείκτη employee, αλλά μου κοπανάει στο compile. > vector<person*> living; employee *e = new employee(); living.pushback(e); employee *f; f=living[0];
MitsakosGR Δημοσ. 12 Ιανουαρίου 2012 Δημοσ. 12 Ιανουαρίου 2012 Έχω μία κλάση person την οποία κληρονομούν οι κλάσεις employees και patients. Τους employees και τους patients τους περνάω όλους σε ένα vector<person*> livings. Θέλω να περάσω το δείκτη livings[0] σε δείκτη employee, αλλά μου κοπανάει στο compile. > vector<person*> living; employee *e = new employee(); living.pushback(e); employee *f; f=living[0]; Τι error message σου βγάζει;;; Δοκίμασε να κάνεις cast τον δείκτη στην κλάση employee: > vector<person*> living; employee *e = new employee(); living.pushback(e); employee *f; f=dynamic_cast<employee*>(living[0]);
defacer Δημοσ. 12 Ιανουαρίου 2012 Δημοσ. 12 Ιανουαρίου 2012 Σκέψου λίγο τι πας να κάνεις. "Βγάζεις" μέσα από τον vector ένα person* και λες στον compiler ότι αυτό είναι στην πραγματικότητα employee*. Πώς όμως μπορείς να είσαι σίγουρος (στη θεωρία) ότι αυτό ισχύει εφόσον θεωρητικά υπάρχουν persons που δεν είναι employees? Αν η απάντηση είναι "όλοι οι pointers που έχω βάλει μέσα στο vector είναι employee* τελεία και παύλα", τότε θα έπρεπε να έχουμε vector<employee*> και όχι vector<person*>. Αν πάλι δεν είναι όλοι οι pointers employee*, τότε αυτό που πας να κάνεις είναι λάθος. Ο compiler λοιπόν διαμαρτύρεται. Σκοπίμως δεν έχω αναφέρει τίποτα για casts διότι αν αρχίσεις να πετάς μέσα casts χωρίς να έχεις σκεφτεί τι πας να κάνεις τότε αυτό που θα καταφέρεις (συνηθισμένη περίπτωση) είναι να κάνεις τον compiler να το βουλώσει και απλά να μεταθέσεις το πρόβλημα για όταν το πρόγραμμά σου τρέχει, οπότε και θα έχουμε πυροτεχνήματα. Τι error message σου βγάζει;;; Δοκίμασε να κάνεις cast τον δείκτη στην κλάση employee: > f=dynamic_cast<employee*>(living[0]); Αυτό που δίνεις είναι πιθανόν λάθος, γιατί δεν επιτρέπεται να κάνεις downcasting με dynamic_cast εκτός κι αν η class έχει τουλάχιστον ένα virtual member (που θα έπρεπε να έχει αλλιώς μιλάμε για προγραμματιστικό λάθος, αλλά αυτό δεν το ξέρουμε και δε νομίζω ότι και ο OP το ξέρει).
ntellos Δημοσ. 13 Ιανουαρίου 2012 Μέλος Δημοσ. 13 Ιανουαρίου 2012 Virtual members: Yes Για να δω τι κλάση είναι το αντικείμενο στην θέση i ελέγχω τι επστρέφει η typeid(*(living)).name() και μετά το κάνω dynamic_cast (ty mitsakosgr για την εντολή και defacer επίσης) ΥΓ: solved
defacer Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 Virtual members: Yes Για να δω τι κλάση είναι το αντικείμενο στην θέση i ελέγχω τι επστρέφει η typeid(*(living)).name() και μετά το κάνω dynamic_cast (ty mitsakosgr για την εντολή και defacer επίσης) ΥΓ: solved Να έχεις υπόψη ότι το τι επιστρέφει η typeid::name είναι implementation-specific (με άλλα λόγια αν αλλάξεις compiler το πρόγραμμα θα δούλευε παλιά στο Texas). Επίσης, αυτό που κάνεις εδώ είναι στην ουσία το λεγόμενο type switching το οποίο είναι κακή ιδέα. Αν θέλεις να φτάσεις σε μια "σωστή" λύση, πες μας ποιό είναι το ζητούμενο εδώ (δηλαδή μην αναλώνεσαι πάνω στη λύση που νομίζεις ότι είναι η σωστή -- γιατί δεν είναι).
bokarinho Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 Σκέψου λίγο τι πας να κάνεις. "Βγάζεις" μέσα από τον vector ένα person* και λες στον compiler ότι αυτό είναι στην πραγματικότητα employee*. Πώς όμως μπορείς να είσαι σίγουρος (στη θεωρία) ότι αυτό ισχύει εφόσον θεωρητικά υπάρχουν persons που δεν είναι employees? Αν η απάντηση είναι "όλοι οι pointers που έχω βάλει μέσα στο vector είναι employee* τελεία και παύλα", τότε θα έπρεπε να έχουμε vector<employee*> και όχι vector<person*>. Αν πάλι δεν είναι όλοι οι pointers employee*, τότε αυτό που πας να κάνεις είναι λάθος. Ο compiler λοιπόν διαμαρτύρεται. Σκοπίμως δεν έχω αναφέρει τίποτα για casts διότι αν αρχίσεις να πετάς μέσα casts χωρίς να έχεις σκεφτεί τι πας να κάνεις τότε αυτό που θα καταφέρεις (συνηθισμένη περίπτωση) είναι να κάνεις τον compiler να το βουλώσει και απλά να μεταθέσεις το πρόβλημα για όταν το πρόγραμμά σου τρέχει, οπότε και θα έχουμε πυροτεχνήματα. Αυτό που δίνεις είναι πιθανόν λάθος, γιατί δεν επιτρέπεται να κάνεις downcasting με dynamic_cast εκτός κι αν η class έχει τουλάχιστον ένα virtual member (που θα έπρεπε να έχει αλλιώς μιλάμε για προγραμματιστικό λάθος, αλλά αυτό δεν το ξέρουμε και δε νομίζω ότι και ο OP το ξέρει). @defacer... Εγώ που δεν καταλαβαίνω μπορείς να μου κάνεις αν έχεις χρόνο ένα παράδειγμα σε κώδικα C++ με 3 κλάσεις για το παραπάνω παράδειγμα;
παπι Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 >class TheBaseClass { public: virtual void Foo() { std::cout<<"Foo baseclass"<<std::endl; } }; class DerivedClassA : public TheBaseClass { public: virtual void Foo() { std::cout<<"Foo derived a"<<std::endl; } virtual void DerivedClassAFunction() { std::cout<<"DerivedClassAFunction"<<std::endl; } }; class DerivedClassB : public TheBaseClass { public: virtual void DerivedClassBFunction() { std::cout<<"DerivedClassBFunction"<<std::endl; }}; > TheBaseClass *pTheBaseClass = new DerivedClassA; DerivedClassB *pDerivedClassB = (DerivedClassB*)pTheBaseClass; pDerivedClassB->DerivedClassBFunction(); // <-- ???? pDerivedClassB->Foo(); // <-- ??? output >DerivedClassAFunction Foo derived a
bokarinho Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 >class TheBaseClass { public: virtual void Foo() { std::cout<<"Foo baseclass"<<std::endl; } }; class DerivedClassA : public TheBaseClass { public: virtual void Foo() { std::cout<<"Foo derived a"<<std::endl; } virtual void DerivedClassAFunction() { std::cout<<"DerivedClassAFunction"<<std::endl; } }; class DerivedClassB : public TheBaseClass { public: virtual void DerivedClassBFunction() { std::cout<<"DerivedClassBFunction"<<std::endl; }}; > TheBaseClass *pTheBaseClass = new DerivedClassA; DerivedClassB *pDerivedClassB = (DerivedClassB*)pTheBaseClass; pDerivedClassB->DerivedClassBFunction(); // <-- ???? pDerivedClassB->Foo(); // <-- ??? output >DerivedClassAFunction Foo derived a Ευχαριστώ παπί, η θεωρία πρέπει να γίνεται και πράξη μερικές φορές για να καταλαβαίνει ο κόσμος.
defacer Δημοσ. 14 Ιανουαρίου 2012 Δημοσ. 14 Ιανουαρίου 2012 @defacer... Εγώ που δεν καταλαβαίνω μπορείς να μου κάνεις αν έχεις χρόνο ένα παράδειγμα σε κώδικα C++ με 3 κλάσεις για το παραπάνω παράδειγμα; Πρώτον, το παράδειγμα του παπιού δεν είναι αυτό που ζήτησες (αν κατάλαβα καλά τι ζήτησες) γιατί χρησιμοποιεί C-style cast και όχι dynamic_cast. Επιπλέον αν κάνεις αυτό που κάνει το παπί στο παράδειγμά του τότε προκύπτει undefined behavior (UB) οπότε θεωρητικά το παράδειγμα δεν στέκει. Σ' αυτό το σημείο για να είμαστε δίκαιοι να πω ότι παρόλο που έχουμε UB, εντούτοις λόγω του τρόπου με τον οποίο κάνουν implement όλοι βασικά οι compilers τις virtual functions το αποτέλεσμα (που θεωρητικά είναι UB) πρακτικά θα είναι αυτό που βλέπεις όπου κι αν το δοκιμάσεις -- και προφανώς το παπί το ξέρει. Τώρα όσο για το παράδειγμα που εγώ κατάλαβα ότι ζήτησες, δες εδώ (λάθος) και εδώ (σωστό). Δε νομίζω πάντως ότι θα δεις κάτι παραπάνω από αυτό που είπα. Η εξήγηση είναι ότι το dynamic_cast οφείλει να επιστρέψει null αν δοκιμάσεις να κάνεις downcast (π.χ. base* σε derived1*) αλλά o pointer δε δείχνει σε αντικείμενο derived1 (μπορεί να δείχνει π.χ. σε base ή σε derived2 κλπ). Αλλά πώς είναι δυνατόν να ξέρει σε τι αντικείμενο δείχνει ένας τυχαίος pointer που του περνάς εσύ; Η απάντηση είναι πως κοιτάει την τιμή του vptr του αντικειμένου που δείχνει ο pointer που περνάς, οπότε μετά ξέρει τι class είναι αυτό το αντικείμενο (αφού υπάρχει ένα προς ένα αντιστοιχια ανάμεσα σε τιμές vptr και polymorphic classes). Για να το κάνει όμως αυτό πρέπει να υπάρχει vptr, που σημαίνει ότι πρέπει η class της οποίας περνάς pointer (ή κάποιος ancestor) να έχει τουλάχιστον μία virtual method. Συνήθως αυτό δεν είναι θέμα γιατί όλες οι classes που προορίζονται για inheritance πρέπει δια ροπάλου να έχουν virtual destructor (για να ξέρει ο compiler ποιον destructor να τρέξει αν κάνεις delete base* ο οποίος στην πραγματικότητα είναι derived* -- δες το λάθος και το σωστό) οπότε καλύπτεται η προϋπόθεση έτσι. Τέλος δεν υπάρχει αντίστοιχο πρόβλημα όταν θέλεις να κάνεις upcast (δηλαδή derived* σε base*) γιατί προφανώς όλα τα αντικείμενα derived ξέρουμε πως είναι και base εξ ορισμού. Αυτός είναι και ο λόγος που για να κάνεις upcast βολεύεσαι και με απλό static_cast και δε χρειάζεσαι ούτε RTTI ενεργοποιημένο ούτε vptr.
παπι Δημοσ. 14 Ιανουαρίου 2012 Δημοσ. 14 Ιανουαρίου 2012 με dynamic cast δεν το κανει compile για αυτο και το static cast για να δει τα προβληματα που δημιουργουνται σε runtime
defacer Δημοσ. 14 Ιανουαρίου 2012 Δημοσ. 14 Ιανουαρίου 2012 με dynamic cast δεν το κανει compile για αυτο και το static cast για να δει τα προβληματα που δημιουργουνται σε runtime Ε ναι αλλά άλλο το ένα, άλλο το άλλο. Άσε που αυτό ήταν C-style, δηλαδή ισοδύναμο με reinterpret_cast.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα