thomason993 Δημοσ. 6 Ιουλίου 2015 Δημοσ. 6 Ιουλίου 2015 Καλησπέρα. Το περασμένο Δεκέμβρη ασχολήθηκα αρκετά με c++ για την υλοποίηση ενός project για την σχολή μου και έμαθα αρκετά πράγματα, ωστόσο έχω ακόμα κάποιες απορίες που δεν πρόλαβα να λύσω έως τώρα λόγω περιορισμένου χρόνου. Μιας και τώρα πλέον έχω περισσότερο χρόνο θέλω να ασχοληθώ περισσότερο και να καλύψω τις απορίες μου. Αρχικά, ποιά είναι η διαφορά ανάμεσα στα αρχεία .h και τα αρχεία .cpp? Ποιός είναι ο σωστός τρόπος να δημιουργήσω μία κλάση χρησιμοποιώντας και τα 2 είδη αρχείων? Μήπως τα αρχεία .h είναι περιττά και μπορώ να ορίσω πλήρως μία κλάση σε ένα .cpp αρχείο? Και επίσης, αν υπάρχει σχέση ανάμεσα σε κάποιες κλάσεις, ποιος είναι ο σωστός τρόπος να "συνδέονται" μεταξύ τους αυτές οι κλάσεις? Π.χ. στο project που είχα φτιάξει υπήρχαν 2 είδη κλάσεων, ας πούμε τις class A και class B. Την class A την είχα υλοποιήσει σε ένα αρχείο .h ενώ την class Β, η οποία είχε και υποκλάσεις και αρκετό περισσότερο κώδικα, την υλοποίησα σε ένα αρχείο .cpp. Στην main δημιουργούσα έναν πίνακα 2 διαστάσεων από δείκτες σε class A. H class Α είχε μία μεταβλητή-μέλος δείκτη σε class B. H class B είχε κάποιες συναρτήσεις οι οποίες έπρεπε να έχουν ως όρισμα αυτό τον 2διάστατο πίνακα δεικτών class A. Θυμάμαι οτι κάπου εκεί υπήρχε πρόβλημα με το compiler καθώς μου έβγαζε οτι γινόταν include το ίδιο αρχείο πολλές φορές ή οτι κάποια κλάση δεν "έβλεπε" κάποια άλλη κλάση επομένως της ήταν άγνωστα τα μέλη της.. Τέλος πάντων, μετά από πολύ trial and error και ψάξιμο στο google, κατέληξα να κάνω στο αρχείο .h της class A ένα forward declaration της class B; , το αρχείο .h που περιείχε την class A το έκανα include στο αρχείο .cpp της class B, και το αρχείο .cpp που περιείχε την class B και τις υποκλάσεις της το έκανα include στο αρχείο main.cpp που περιείχε την main. Επίσης, αναγκαστικά, κάποιες από τις συναρτήσεις των υποκλάσεων της class B δεν γινόταν να τις υλοποιήσω στο αρχείο .cpp που περιείχε την class Β και γι' αυτό τις συγκεκριμένες συναρτήσεις τις υλοποίησα στο αρχείο main.cpp (π.χ. void B::operation1(A*** map); ). Δεν ξέρω δυστυχώς για ποιον λόγο χρειάστηκαν οι παραπάνω αλλαγές στον κώδικα και πως ακριβώς διόρθωσαν το πρόβλημα καθώς δεν είχα χρόνο τότε να ψαχτώ περισσότερο.. Το ξέρω οτι είναι αρκετά περίπλοκο το ερώτημά μου και ίσως και να μην το θέτω σωστά, καθώς έχει περάσει καιρός από τότε που έκανα το project, αλλά αν κάποιος έχει την όρεξη να ρίξει μια ματιά και να μου εξηγήσει τι ακριβώς μπέρδεμα γινόταν με τις κλάσεις και όλες αυτές τις δηλώσεις και τα include, θα με βοηθούσε πολύ. Επίσης, αν κάποιος θέλει, μπορώ να του στείλω τον κώδικα από το project μήπως και βγάλει καλύτερα συμπεράσματα από εκεί. Ευχαριστώ!
παπι Δημοσ. 6 Ιουλίου 2015 Δημοσ. 6 Ιουλίου 2015 Τα αρχεια δεν εχουν καμια σημασια για τον compiler. Ειναι πρακτικα ενας τροπος οργανωσης του project. Δηλαδη. Τα αρχεια cpp ειναι αρχεια τα οποια περιεχουν definitions, και ειναι αυτα τα αρχεια τα οποια γινονται compile σε object. Τα αρχεια h ειναι αρχεια τα οποια περιεχουν declaration, αυτα τα αρχεια δεν γινονται compile, αυτα γινονται copy-paste με το keyword #include.
thomason993 Δημοσ. 6 Ιουλίου 2015 Μέλος Δημοσ. 6 Ιουλίου 2015 Ευχαριστώ για την άμεση απάντηση. Σύμφωνα με αυτό που είπες, έκανα copy-paste όλα τα περιεχόμενα του αρχείου classA.h στο αρχείο classB.cpp και το πρόγραμμα γίνεται και πάλι compile κανονικά. Πλέον το αρχείο classB.cpp είναι της μορφής: class B; class A{ B* Bptr; } class B{ } Δηλαδή, η δήλωση class B; πάνω από την class A{...} απλά δηλώνει οτι κάπου υπάρχει στο αρχείο η κλάση B επομένως να μην βγάζει error οτι δεν την βρίσκει.. Σωστά? Μία άλλη απορία τώρα. Αν έχω τις κλάσεις: class A{...} class C; class B: public A{ void f(A *ptr){ if(dynamic_cast<C *>(ptr)==0){...} } } class C: public B{...} Για ποιό λόγο βγάζει error στην dynamic_cast το εξής: "cannot dynamic_cast `ptr' (of type `class A*') to type `struct C*' (target is not pointer or reference to complete type) " Αυτό για ποιον λόγο γίνεται εφόσον το ptr είναι δείκτης?
defacer Δημοσ. 6 Ιουλίου 2015 Δημοσ. 6 Ιουλίου 2015 Το dynamic_cast χρειάζεται πλήρες definition του type στο οποίο μετατρέπεις. Αν κατάλαβα καλά σε παραξενεύει το ότι άλλα cast δεν το χρειάζονται αυτό, όμως ξεχνάς το εξής σημαντικό (παρόλο που ο κώδικας που δίνεις σαν παράδειγμα δεν το ξεχνάει καθόλου): το dynamic_cast υπόσχεται πως αν ζητάς αρλούμπες θα το καταλάβει και θα σου επιστρέψει null pointer, σε αντίθεση με τα άλλα cast που δίνουν compile time error ή undefined behavior ανάλογα την περίπτωση. Επομένως πρέπει να μπορεί να καταλάβει αν ζητάς αρλούμπες, και για να γίνει αυτό χρειάζεται το type definition (και ενεργοποιημένο RTTI όταν κάνεις compile).
thomason993 Δημοσ. 6 Ιουλίου 2015 Μέλος Δημοσ. 6 Ιουλίου 2015 Απ' οτι διάβασα στο wiki, το RTTI είναι διαθέσιμο μόνο για polymorphic κλάσεις, δηλ. κλάσεις με μία τουλάχιστον virtual συνάρτηση (εύκολο να γίνει). Όταν λες οτι το dynamic_cast για να λειτουργήσει σωστά χρειάζεται το type definition τι εννοείς? Πρέπει το body της κλάσης κλάσης Α και της κλάσης C να βρίσκεται πριν το body της void f(A* ptr) ?
παπι Δημοσ. 7 Ιουλίου 2015 Δημοσ. 7 Ιουλίου 2015 Type definition, ( βασικά declaration αλλά δεν παίρνω όρκο) είναι το αντίθετο από αυτό που έχεις ( forward declaration ) Anyway, για να βγαλεις το dynamic cast, φτιάξει ένα interface.
thomason993 Δημοσ. 7 Ιουλίου 2015 Μέλος Δημοσ. 7 Ιουλίου 2015 Τελικά αν υλοποιήσω το σώμα της void f έξω από την κλάση Β, γίνεται compile κανονικά και δεν χρειάζεται ούτε το forward declaration class C; Κάπως έτσι δηλαδή: class A{ public: virtual ~A(){ } }; class B: public A{ public: void f(A* ptr); }; class C: public B{...}; void B::f(A* ptr){ if(dynamic_cast<C *>(ptr)==0){...} } Type definition, ( βασικά declaration αλλά δεν παίρνω όρκο) είναι το αντίθετο από αυτό που έχεις ( forward declaration )Anyway, για να βγαλεις το dynamic cast, φτιάξει ένα interface. Πως ακριβώς εννοείς να βγάλω την dynamic_cast με interface? Στο google για interface στη c++ λένε να φτιάξεις μία abstract κλάση, αλλά δεν καταλαβαίνω πως μπορώ να το χρησιμοποιήσω αυτό για να βγάλω το dynamic_cast.
παπι Δημοσ. 7 Ιουλίου 2015 Δημοσ. 7 Ιουλίου 2015 Ανέβασε το projwct ( εάν έχεις github θα ήταν gg) να δω να σου πω πάνω σε αυτό. Τελικά αν υλοποιήσω το σώμα της void f έξω από την κλάση Β, γίνεται compile κανονικά και δεν χρειάζεται ούτε το forward declaration class C; Κάπως έτσι δηλαδή: Αυτο που λεγαμε για το type declaration. Το πως και το γιατι, απλα ο c++ compiler κανει compile απο πανω προς τα κατω. πχ αυτο ειναι σωστο σε javascript print('hello'); function print(text){ console.log(text); } ενω κατι αντιστοιχο σε c++ ειναι λαθος, και θα σου βγαλει undefined 'print'
thomason993 Δημοσ. 7 Ιουλίου 2015 Μέλος Δημοσ. 7 Ιουλίου 2015 Γίνεται ένας χαμός και δεν ξέρω αν θα βγάλεις εύκολα άκρη.. GitHub δεν έχω αλλά και πάλι δεν ξέρω πως δουλεύει. Κατέβασέ το από εδώ και πες μου όταν είναι για να το ξανασβήσω.. https://www.dropbox.com/sh/fqpotm6xxn2o2ww/AACpnwq83ReD9pcDUmB-5lqca?dl=0 Η συναρτήσεις που έχουν dynamic_cast είναι στο αρχείο main.cpp (όλες οι συναρτήσεις με όνομα ship::FUNC_NAME)
παπι Δημοσ. 7 Ιουλίου 2015 Δημοσ. 7 Ιουλίου 2015 Ακρη βγαζω, απλα δεν εκμεταλλευεσε τις δυνατοτητες του OOP
thomason993 Δημοσ. 7 Ιουλίου 2015 Μέλος Δημοσ. 7 Ιουλίου 2015 χαχαχαχα παραιτείσαι κι εσύ ε? ε ήταν η πρώτη απόπειρα στην c++ και δεν είχα καθόλου χρόνο οπότε ήταν λίγο τσαπατσουλιά.. γι αυτό είπα να κάτσω να ασχοληθώ λίγο περισσότερο τώρα που υπάρχει χρόνος..
παπι Δημοσ. 7 Ιουλίου 2015 Δημοσ. 7 Ιουλίου 2015 Πρεπει να κανεις κατι με το abstraction, για να μην εχεις αυτο το κατεβατο. Πχ, ολο αυτο με το interface (UI) σου "βαζει" κωδικα που δε θες.
thomason993 Δημοσ. 7 Ιουλίου 2015 Μέλος Δημοσ. 7 Ιουλίου 2015 Ζητούσε η εκφώνηση να υπάρχει μία κύρια abstract κλάση και όλες οι υποκλάσεις να κληρονομούν από αυτή και να επικαλύπτουν τις μεθόδους της.. Ξέρω οτι σίγουρα θα μπορούσα να έχω κάνει κάποια πράγματα με λιγότερο κόπο ή πιο έξυπνα αλλά δεν το κατέχω τόσο πολύ ακόμα.. Τις βασικές απορίες που είχα τουλάχιστον τις κάλυψα, αυτό κυρίως με το πως δουλεύει το dynamic_cast και γιατί η μία κλάση πρέπει να είναι δηλωμένη μετά την άλλη για να τις βλέπει από πάνω προς το κάτω ο compiler.. Θα ψάξω να βρω κανένα θεματάκι να ασχοληθώ μέσα στο καλοκαίρι.. Σκεφτόμουν κάποιο πρόγραμμα που να λύνει sudoku ίσως (αν και αυτό δεν χρειάζεται απαραίτητα αντικειμενοστρέφεια) Εκτός απο video στο youtube, κάποιο άλλο site για να διαβάσω για γραφικά στη c++ έχεις να προτείνεις?
παπι Δημοσ. 7 Ιουλίου 2015 Δημοσ. 7 Ιουλίου 2015 Δεν ειναι γραφικα στη c++, αλλα γραφικα στο whateva framework με c++. πχ στα windows (μαμα) εχεις το gdi που ειναι αρκετα φτωχο και παραλληλα οτι πρεπει για εκμαθηση. εχεις και αλλα οπως το qt (οχι μαμα) που ειναι "oop", το kde, κλπ που ειναι πλουσια σε δυνατοτητες. Διαλεγεις, διαβαζεις, ρωτας οτι σε δυσκολευει.
thomason993 Δημοσ. 7 Ιουλίου 2015 Μέλος Δημοσ. 7 Ιουλίου 2015 Καλώς, θα ξεκινήσω και οτι απορία προκύπτει στη πορεία θα ρωτάω.. Ευχαριστώ για τη βοήθεια!
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα