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

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

Δημοσ.

Καλησπέρα.

 

Το περασμένο Δεκέμβρη ασχολήθηκα αρκετά με 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 μήπως και βγάλει καλύτερα συμπεράσματα από εκεί.

 

Ευχαριστώ! :)

Δημοσ.

Τα αρχεια δεν εχουν καμια σημασια για τον compiler. Ειναι πρακτικα ενας τροπος οργανωσης του project. Δηλαδη.

 

Τα αρχεια cpp ειναι αρχεια τα οποια περιεχουν definitions, και ειναι αυτα τα αρχεια τα οποια γινονται compile σε object.

 

Τα αρχεια h ειναι αρχεια τα οποια περιεχουν declaration, αυτα τα αρχεια δεν γινονται compile, αυτα γινονται copy-paste με το keyword #include.

Δημοσ.

Ευχαριστώ για την άμεση απάντηση.

 

Σύμφωνα με αυτό που είπες, έκανα 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 είναι δείκτης?

Δημοσ.

Το dynamic_cast χρειάζεται πλήρες definition του type στο οποίο μετατρέπεις. Αν κατάλαβα καλά σε παραξενεύει το ότι άλλα cast δεν το χρειάζονται αυτό, όμως ξεχνάς το εξής σημαντικό (παρόλο που ο κώδικας που δίνεις σαν παράδειγμα δεν το ξεχνάει καθόλου): το dynamic_cast υπόσχεται πως αν ζητάς αρλούμπες θα το καταλάβει και θα σου επιστρέψει null pointer, σε αντίθεση με τα άλλα cast που δίνουν compile time error ή undefined behavior ανάλογα την περίπτωση. Επομένως πρέπει να μπορεί να καταλάβει αν ζητάς αρλούμπες, και για να γίνει αυτό χρειάζεται το type definition (και ενεργοποιημένο RTTI όταν κάνεις compile).

Δημοσ.

Απ' οτι διάβασα στο wiki, το RTTI είναι διαθέσιμο μόνο για polymorphic κλάσεις, δηλ. κλάσεις με μία τουλάχιστον virtual συνάρτηση (εύκολο να γίνει).

Όταν λες οτι το dynamic_cast για να λειτουργήσει σωστά χρειάζεται το type definition τι εννοείς?

Πρέπει το body της κλάσης κλάσης Α και της κλάσης C να βρίσκεται πριν το body της void f(A* ptr) ?

Δημοσ.

Type definition, ( βασικά declaration αλλά δεν παίρνω όρκο) είναι το αντίθετο από αυτό που έχεις ( forward declaration )

 

Anyway, για να βγαλεις το dynamic cast, φτιάξει ένα interface.

Δημοσ.

Τελικά αν υλοποιήσω το σώμα της 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.

Δημοσ.

Ανέβασε το 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'

Δημοσ.

Γίνεται ένας χαμός και δεν ξέρω αν θα βγάλεις εύκολα άκρη.. GitHub δεν έχω αλλά και πάλι δεν ξέρω πως δουλεύει.

 

Κατέβασέ το από εδώ και πες μου όταν είναι για να το ξανασβήσω..

https://www.dropbox.com/sh/fqpotm6xxn2o2ww/AACpnwq83ReD9pcDUmB-5lqca?dl=0

 

Η συναρτήσεις που έχουν dynamic_cast είναι στο αρχείο main.cpp (όλες οι συναρτήσεις με όνομα ship::FUNC_NAME)

Δημοσ.

χαχαχαχα παραιτείσαι κι εσύ ε? :P

 

ε ήταν η πρώτη απόπειρα στην c++ και δεν είχα καθόλου χρόνο οπότε ήταν λίγο τσαπατσουλιά.. γι αυτό είπα να κάτσω να ασχοληθώ λίγο περισσότερο τώρα που υπάρχει χρόνος..

Δημοσ.

Πρεπει να κανεις κατι με το abstraction, για να μην εχεις αυτο το κατεβατο. Πχ, ολο αυτο με το interface (UI) σου "βαζει" κωδικα που δε θες.

Δημοσ.

Ζητούσε η εκφώνηση να υπάρχει μία κύρια abstract κλάση και όλες οι υποκλάσεις να κληρονομούν από αυτή και να επικαλύπτουν τις μεθόδους της..

Ξέρω οτι σίγουρα θα μπορούσα να έχω κάνει κάποια πράγματα με λιγότερο κόπο ή πιο έξυπνα αλλά δεν το κατέχω τόσο πολύ ακόμα..

Τις βασικές απορίες που είχα τουλάχιστον τις κάλυψα, αυτό κυρίως με το πως δουλεύει το dynamic_cast και γιατί η μία κλάση πρέπει να είναι δηλωμένη μετά την άλλη για να τις βλέπει από πάνω προς το κάτω ο compiler..

 

Θα ψάξω να βρω κανένα θεματάκι να ασχοληθώ μέσα στο καλοκαίρι.. Σκεφτόμουν κάποιο πρόγραμμα που να λύνει sudoku ίσως (αν και αυτό δεν χρειάζεται απαραίτητα αντικειμενοστρέφεια)

 

Εκτός απο video στο youtube, κάποιο άλλο site για να διαβάσω για γραφικά στη c++ έχεις να προτείνεις?

Δημοσ.

Δεν ειναι γραφικα στη c++, αλλα γραφικα στο whateva framework με c++.

 

πχ στα windows (μαμα) εχεις το gdi που ειναι αρκετα φτωχο και παραλληλα οτι πρεπει για εκμαθηση.

εχεις και αλλα οπως το qt (οχι μαμα) που ειναι "oop", το kde, κλπ που ειναι πλουσια σε δυνατοτητες.

 

Διαλεγεις, διαβαζεις, ρωτας οτι σε δυσκολευει.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...