Εργαστήριο Τεχνολογίας Λογισμικού
+2 votes
230 views

Μια απορία με βάση ερώτηση που τέθηκε στην σημερινή διάλεξη για την κλήση της συνάρτησης v() της κλάσης Α κατά την κατασκευή αντικειμένου της κλάσης Β αν και ήταν virtual και γινόταν override από την v() της Β.

Αν όπως περιμέναμε καλούνταν της Β κατά την κλήση του constructor δεν θα είχαμε πρόβλημα αν στην v() της Β είχαμε κάποιο τύπωμα μεταβλητής που αρχικοποιούνταν μέσα στις αγκύλες του constructor της Β (ίσως δηλαδή δικαιολογείται η επιλογή αυτή της C++); π.χ.

in progtech by (270 points) | 230 views

1 Answer

0 votes

Μετά από μια (σύντομη) έρευνα στο διαδίκτυο φαίνεται πως ο λόγος που ο constructor της A θα καλέσει την foo της A και όχι της Β, είναι πως αν στην κλάση Β υπάρχουν μεταβλητές που είναι αντικείμενα άλλων κλάσεων, ο constructor αυτών θα κληθεί μετά τον constructor της Α και πριν τον constructor της B.

Για παράδειγμα αν στην Β υπάρχει μια μεταβλητή mystack τύπου stack ο constructor αυτής θα κληθεί μετά τον constructor του A αλλά πριν τον constructor του Β. Ας θεωρήσουμε ότι καλούμε την foo από τον constructor την Α και η C++ επιλέγει να καλέσει την foo της Β. Τότε, αν η foo της Β καλέσει κάποια μέθοδο της mystack (για παράδειγμα προσθέσει κάποιο στοιχείο σε αυτήν), τότε αυτή θα καλούνταν πριν τον constructor της mystack γεγονός το οποίο προφανώς δεν θέλουμε να συμβεί.

Άρα αν ο προγραμματιστής ήθελε να συντάξει μια foo εντός της κλάσης Β, η οποία να κληθεί από τον constructor της κλάσης Α, θα έπρεπε να λάβει υπόψη του ότι μπορεί να τροποποιήσει μόνο μεταβλητές που είναι της κλάσης Α (και άρα έχουν ήδη αρχικοποιηθεί πριν την κλήση του constructor της Α). Φυσικά αυτό είναι ιδιαίτερα επιρρεπές σε bugs, οπότε οι σχεδιαστές της C++ επέλεξαν να μην το επιτρέψουν.

by (2.9k points)
+1

Θα συμφωνήσω, αλλά θεωρώ δεν είναι ανάγκη να μιλήσουμε για αντικείμενα. Το παράδειγμα που δίνω (στο οποίο τυχόν κλήση της v() της Β θα τύπωνε μια μη-αρχικοποιημένη μεταβλητή) νομίζω είναι ένα πιο απλό και άμεσο πρόβλημα που προκύπτει.

+1

Σε τελική ανάλυση θίγουμε το ίδιο πρόβλημα, εφόσον η κατασκευή τυχόντων επιπρόσθετων μεταβλητών της κλάσης Β ουσιαστικά θα εκτελεστεί μαζί με τον constructor του Β (πριν από αυτόν). Ο λόγος που το έθεσα έτσι είναι πως κάποιος θα μπορούσε να ισχυριστεί ότι μπορεί ίσως εύκολα να λάβει υπόψη του στην σύνταξη της foo της Β ότι δεν έχουν εκτελεστεί αυτά που ο ίδιος έγραψε στον constructor της Β. Όμως το να λάβει υπόψη του ότι δεν έχουν κατασκευαστεί ακόμα οι μεταβλητές της κλάσης Β θα ήταν πιο δύσκολο.

+2

Μια ακομη λογικη εξηγηση, επεκταση αυτης και εκεινης που αναφερθηκε στην διαλεξη, για τον destructor, ειναι οτι για καθε derived class καλειται αυτοματα και ο καταστροφεας της base class. Μια συντομη αναλυση γιατι αποτυγχανει το override βρισκεται στην απαντηση αυτης της ερωτησης:
https://stackoverflow.com/questions/3261694/why-base-class-destructor-virtual-is-called-when-a-derived-class-object-is-del

301 questions

289 answers

288 comments

770 users