balios Δημοσ. 24 Οκτωβρίου 2013 Δημοσ. 24 Οκτωβρίου 2013 Μου έχει γεννηθεί η εξής απορία ας υποθέσουμε ότι έχω μία κλάση test η οποία έχει 2 member variables x,y class test { private: int x; int y; public: test(int a,int ; }; και έστω ότι θέλω να υλοποιήσω τον constructor της κλάσης που αρχικοποιεί αυτές τις δύο μεταβλητές Aν υλοποιήσω constructor με default value ορίσματα νομίζω αυτό πρέπει να γίνει στη δήλωση του constructor μέσα στην κλάση πχ test(int a=3,int b=3); κατα τον ορισμό του constructor θα πρέπει να γράψω test::test(int a,int { x=a; y=b; } Η κλήση τοτε του constructor μέσα στη Main σαν test() θα λειτουργήσει όπως θέλω? δηλαδή αρχικοποίηση των μεταβλητών x,y του αντικειμένου στις default τιμες? δεν μπερδευέται ο compiler Με την μή δήλωση no argument constructor? Μπορώ να υλοποιήσω και τον no argument constructor Και αν ναι τοτε πως καταλαβαίνει ο constructor ποτε πρέπει να κληθεί ο No argument constructor ή ο constructor Με δύο ορίσματα αλλα με default τιμές?
defacer Δημοσ. 25 Οκτωβρίου 2013 Δημοσ. 25 Οκτωβρίου 2013 Πρώτον, γιατί δεν το δοκιμάζεις μόνος σου; Θα ήταν πολύ ευκολότερο από το να περιμένεις απάντηση από αλλού. Επι της ουσίας τώρα, αν βάλεις public constructor με all default arguments και public default constructor (δηλαδή χωρίς ορίσματα, προσοχή στη λεπτή διαφορά στην ορολογία) θα υπάρχει αμφισημία (ambiguity) σχετικά με το ποιός constructor πρέπει να χρησιμοποιηθεί και το πρόγραμμα δε θα κάνει compile. Το ζήτημα που θέτεις όμως έχει αρκετό ψωμί γιατί ανοίγει την πόρτα για να αναφέρουμε ότι: Αν βάλεις constructor που έχει όλα (ή όλα εκτός από ένα) τα ορίσματα με default τιμές τότε καλό είναι να σκεφτείς αν πρέπει να τον κάνεις explicit. Αν δεν το κάνεις αυτό τότε μπορεί κανείς να γράψει π.χ. test t = 5, το οποίο μπορεί να βγάζει νόημα ή μπορεί και όχι. Τα members της class τα αρχικοποιείς όπου είναι δυνατόν με initialization list, όχι μέσα στον constructor. Επομένως: test(int a = 1, int b = 2) : x(a), y( { /* και τίποτα εδώ μέσα */ } Είναι κακή συνήθεια να βάζεις default τιμές στα ορίσματα συναρτήσεων (συμπεριλαμβανομένων των constructors) όταν γράφεις μια βιβλιοθήκη. Αυτό διότι η default τιμές γίνονται compile μέσα στον κώδικα που καλεί τη συνάρτηση, και όχι στον κώδικα της ίδιας της συνάρτησης. Το οποίο σημαίνει πως αν κάποιος κάνει link ένα binary από τη βιβλιοθήκη σου χρησιμοποιώντας αναφορά σε διαφορετικής έκδοσης header από αυτό με το οποίο έγινε compile το binary (πράγμα το οποίο γίνεται πολύ πολύ άνετα χωρίς να το καταλάβεις) οι κλήσεις στη συνάρτηση θα παίρνουν "λάθος" τιμές στα default arguments. Κατ' επέκταση για να αλλάξουν οι default τιμές απαιτείται recompile του κώδικα που σε καλεί, (όχι μόνο του κώδικα της βιβλιοθήκης), πράγμα που σημαίνει ότι αυτές θα πρέπει να αντιμετωπίζονται με τον ίδιο σεβασμό όπως π.χ. τα ονόματα των functions. Αυτό όμως δεν είναι τόσο προφανές και συχνά καταλήγουμε σε λάθη. Με το πρότυπο C++11 μπορείς πλέον να βάζεις default τιμές στα ορίσματα των constructors χωρίς τα παραπάνω προβλήματα χρησιμοποιώντας constructor delegation: test() : test(1, 2) {} // delegated constructor test(int a, int : x(a), y( {} 3
balios Δημοσ. 16 Δεκεμβρίου 2013 Μέλος Δημοσ. 16 Δεκεμβρίου 2013 ησουν κατατοπιστικός! Δεν είχα σκοπο να το χρησιμοποιήσω ποτέ στον κωδικά μου με τέτοιο τρόπο η ερώτηση ήταν κάπως φιλοσοφική Πρώτον, γιατί δεν το δοκιμάζεις μόνος σου; Θα ήταν πολύ ευκολότερο από το να περιμένεις απάντηση από αλλού. Επι της ουσίας τώρα, αν βάλεις public constructor με all default arguments και public default constructor (δηλαδή χωρίς ορίσματα, προσοχή στη λεπτή διαφορά στην ορολογία) θα υπάρχει αμφισημία (ambiguity) σχετικά με το ποιός constructor πρέπει να χρησιμοποιηθεί και το πρόγραμμα δε θα κάνει compile. Το ζήτημα που θέτεις όμως έχει αρκετό ψωμί γιατί ανοίγει την πόρτα για να αναφέρουμε ότι: Αν βάλεις constructor που έχει όλα (ή όλα εκτός από ένα) τα ορίσματα με default τιμές τότε καλό είναι να σκεφτείς αν πρέπει να τον κάνεις explicit. Αν δεν το κάνεις αυτό τότε μπορεί κανείς να γράψει π.χ. test t = 5, το οποίο μπορεί να βγάζει νόημα ή μπορεί και όχι. Τα members της class τα αρχικοποιείς όπου είναι δυνατόν με initialization list, όχι μέσα στον constructor. Επομένως: test(int a = 1, int b = 2) : x(a), y( { /* και τίποτα εδώ μέσα */ } Είναι κακή συνήθεια να βάζεις default τιμές στα ορίσματα συναρτήσεων (συμπεριλαμβανομένων των constructors) όταν γράφεις μια βιβλιοθήκη. Αυτό διότι η default τιμές γίνονται compile μέσα στον κώδικα που καλεί τη συνάρτηση, και όχι στον κώδικα της ίδιας της συνάρτησης. Το οποίο σημαίνει πως αν κάποιος κάνει link ένα binary από τη βιβλιοθήκη σου χρησιμοποιώντας αναφορά σε διαφορετικής έκδοσης header από αυτό με το οποίο έγινε compile το binary (πράγμα το οποίο γίνεται πολύ πολύ άνετα χωρίς να το καταλάβεις) οι κλήσεις στη συνάρτηση θα παίρνουν "λάθος" τιμές στα default arguments. Κατ' επέκταση για να αλλάξουν οι default τιμές απαιτείται recompile του κώδικα που σε καλεί, (όχι μόνο του κώδικα της βιβλιοθήκης), πράγμα που σημαίνει ότι αυτές θα πρέπει να αντιμετωπίζονται με τον ίδιο σεβασμό όπως π.χ. τα ονόματα των functions. Αυτό όμως δεν είναι τόσο προφανές και συχνά καταλήγουμε σε λάθη. Με το πρότυπο C++11 μπορείς πλέον να βάζεις default τιμές στα ορίσματα των constructors χωρίς τα παραπάνω προβλήματα χρησιμοποιώντας constructor delegation: test() : test(1, 2) {} // delegated constructor test(int a, int : x(a), y( {}
Caiden Δημοσ. 21 Φεβρουαρίου 2014 Δημοσ. 21 Φεβρουαρίου 2014 Καλησπερα επαναφερω το θεμα (να μην ανοιγω καινουργιο) καθως εχω μια απορια στην αρχικοποιηση τιμων μεσω constructors αλλα σε συνθετες κλασεις. Ακολουθει ενας απλος ενδεικτικος κωδικας για να καταλαβετε τι θελω να πω. #include <iostream> using namespace std; class C { private: int count; public: C(int timh){count=timh;}; ~C(); }; class B { public: B(); ~B(); C eswterikh_klassh; }; class A { public: A(); ~A(); C exwterikh_prwth; B exwterikh_deuterh }; int main() { int metavliti; cin >> metavliti; A klassh; return 0; } Εγω θελω μεσω των constructors να αρχικοποιησω την μεταβλητη της κλασσης C "count" στην τιμη της μεταβλητης "metavliti" που διαβασα στην main. Ξερω οτι πρεπει να περασω διαδοχικα την τιμη απο ολους τους constructors (Α --> Β --> C) απλα μπερδευομαι πως θα συνδεθουν μεταξυ τους οπως επισης πως θα πρεπει να τους καλεσω στην main (τον constructor της Α)
defacer Δημοσ. 23 Φεβρουαρίου 2014 Δημοσ. 23 Φεβρουαρίου 2014 Πρώτον, γιατί έβαλες την class Α στο παράδειγμα εφόσον δεν έχεις βρει ακόμα πώς να το κάνεις με την class B σκέτο; Δεύτερο, και σχετικό με την class C: αυτά που έγραψα παραπάνω (συγκεκριμένα το #2) τα διάβασες;
Caiden Δημοσ. 23 Φεβρουαρίου 2014 Δημοσ. 23 Φεβρουαρίου 2014 Πρώτον, γιατί έβαλες την class Α στο παράδειγμα εφόσον δεν έχεις βρει ακόμα πώς να το κάνεις με την class B σκέτο; Δεύτερο, και σχετικό με την class C: αυτά που έγραψα παραπάνω (συγκεκριμένα το #2) τα διάβασες; Εχεςι δικιο για το πρωτο, ας το φτιαξω πρωτα με τις κλασσεις B και C και μετα συνεχιζω και για την A. Ναι φυσικα τα διαβασα. Βασικα το προβλημα μου ειναι αν στους ενδιαμεσους constructors θα πρεπει να γραψω καποια μορφη κωδικα ή ο εσωτερικος constructor θα βλεπει τα ορισματα απο τον εξωτερικο. Δηλαδη θα περναω τα ορισματα διαδοχικα σε ολους και οταν θελω να γινει η αρχικοποιηση να το χρησιμοποιω στην μεταβλητη που θελω
Caiden Δημοσ. 23 Φεβρουαρίου 2014 Δημοσ. 23 Φεβρουαρίου 2014 Λοιπον απο την αρχη. Οταν εχουμε τις κλασσεις B και C ο constructor της B περνει σαν ορισμα την μεταβλητη που θελουμε και αντιστοιχα το ιδιο ο constructor της C. Οταν καλεστει ο constructor της B στην συνεχεια δεν θα καλεστει και αυτος της C? με τον οποιο θα γινει και η αρχικοποιηση. Σορρυ αν τα γραφω καπως απλα προσπαθω να καταλαβω την λογικη constructors και destructors
defacer Δημοσ. 24 Φεβρουαρίου 2014 Δημοσ. 24 Φεβρουαρίου 2014 (Προαιρετικά) αλλάζεις τον constructor της C ώστε να χρησιμοποιεί initialization list. Κι έτσι τον έχεις να αρχικοποιεί ένα member με την τιμή που περνάς: class C { private: int count; public: C(int timh) : count(timh) {}; }; Εδώ το count(timh) είναι αντίστοιχο με το να γράψεις π.χ. κάπου int lol(42); μόνο που το count είναι member αντί για local variable. Και μετά γράφεις τον constructor της B ακριβώς με τον ίδιο τρόπο: class B { private: C eswterikh_klassh; public: B(int timh) : eswterikh_klassh(timh) {}; }; Κι εδώ το eswterikh_klassh(timh) είναι σα να γράφεις κάπου C eswterikh_klassh(timh), δηλαδή θα κληθεί βέβαια ο αντίστοιχος constructor, μόνο που το αντικείμενο C είναι member. 2
Caiden Δημοσ. 24 Φεβρουαρίου 2014 Δημοσ. 24 Φεβρουαρίου 2014 Α μαλιστα σε ευχαριστω πολυ τωρα το καταλαβα. Αν εχω περισσοτερες εσωτερικες κλασσεις τοτε στον constructor του B θα γραψω B(int timh) : eswterikh_klassh(timh), allh_klassh(timh) {}; Δηλαδη ουστιαστικα παρεμβαινω και καλω τον δικο μου constructor ετσι ωστε να μην χρησιμοποιηθει ο default αν καταλαβα σωστα 1
Bluezy Δημοσ. 24 Φεβρουαρίου 2014 Δημοσ. 24 Φεβρουαρίου 2014 Α μαλιστα σε ευχαριστω πολυ τωρα το καταλαβα. Αν εχω περισσοτερες εσωτερικες κλασσεις τοτε στον constructor του B θα γραψω B(int timh) : eswterikh_klassh(timh), allh_klassh(timh) {}; Δηλαδη ουστιαστικα παρεμβαινω και καλω τον δικο μου constructor ετσι ωστε να μην χρησιμοποιηθει ο default αν καταλαβα σωστα O constructor της Β o οποίος παίρνει σαν όρισμα το int timh θα τρέξει κανονικά. Εγώ ξέρω ότι όταν λες default constructor μιας κλάσης/αντικειμένου εννοείς αυτον : ονομα_κλάσης() { } Απλώς εδώ με το member initializer list ουσιαστικά μπορείς να θέσεις σε κάθε αντικείμενο σου όπως τα eswterikh_klash και allh_klash την μεταβλητή timi απευθείας από την εκκίνηση του constructor B(int timi).
Caiden Δημοσ. 24 Φεβρουαρίου 2014 Δημοσ. 24 Φεβρουαρίου 2014 O constructor της Β o οποίος παίρνει σαν όρισμα το int timh θα τρέξει κανονικά. Εγώ ξέρω ότι όταν λες default constructor μιας κλάσης/αντικειμένου εννοείς αυτον : ονομα_κλάσης() { } Απλώς εδώ με το member initializer list ουσιαστικά μπορείς να θέσεις σε κάθε αντικείμενο σου όπως τα eswterikh_klash και allh_klash την μεταβλητή timi απευθείας από την εκκίνηση του constructor B(int timi). Ναι ναι αυτο εννοω οταν λεω default constructor. Σας ευχαριστω ολους για την βοηθεια. Αν εχω καποια αλλη ερωτηση θα επανελθω
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα