CookieMonster80 Δημοσ. 21 Δεκεμβρίου 2016 Δημοσ. 21 Δεκεμβρίου 2016 Καλησπέρα μπαίνω αμέσως στο θέμα/σεντόνι . Έστω ότι έχουμε: class A{ } Και υποκλάσσεις B,C,D, κτλ της μορφής: class B:public A{ } Κάποιες από τις υποκλάσσεις μπορούν να αλληλεπιδράσουν μεταξύ τους και κάποιες άλλες όχι. Δηλαδή θέλω κάτι του στυλ: A* b = new B(); A* d = new D(); b->doSomething(*d) Αλλά δεν μπορώ να χρησιμοποιήσω κάποιο id/enum κτλ για να τις ξεχωρίζω και δεν μπορώ να καταλάβω πως μπορώ να το υλοποιήσω. Σκέφτηκα να υπάρχει στην Α κάτι τέτοιο virtual doSomething(A& {} virtual doSomething(A& c) {} . . κτλ Και στην υποκλάσση/σεις που υπάρχει αλληλεπίδραση να κάνω implementation μόνο αυτών που θέλω έτσι ώστε να υπάρχει η κατάλληλη λειτουργία. Το πρόβλημα με το παραπάνω είναι ότι αυτό: A* b = new B(); D d; b->doSomething(d) δουλεύει γιατί ξέρει οτι το d είναι τύπου D και υπάρχει τέτοια συνάρτηση αλλά το ζητούμενο: A* b = new B(); A* d = new D(); b->doSomething(*d); Προφανώς δεν δουλεύει επειδή δεν μπορεί να κάνει μετατροπή από Α στα παιδιά της. Θα εκτιμούσα αν υπήρχε κάποια βοήθεια/κάπου να δω παρόμοια παραδείγματα για να καταλάβω τι πρέπει να κάνω. Υ.Γ Όχι dynamic cast και όχι typeof/typeid.
Moderators Kercyn Δημοσ. 21 Δεκεμβρίου 2016 Moderators Δημοσ. 21 Δεκεμβρίου 2016 Δεν κατάλαβα (σχεδόν) τίποτα. 2
CookieMonster80 Δημοσ. 21 Δεκεμβρίου 2016 Μέλος Δημοσ. 21 Δεκεμβρίου 2016 Δεν κατάλαβα (σχεδόν) τίποτα. Λοιπόν ξαναπροσπαθώ: Έχουμε class A{ virtual void doSomething(B& {} virtual void doSomething(C& c) {} . . virtual void doSomething(F& f) {} }; class B:public A{ void doSomething(C& c){ cout << "B is doing something with C"; } }; class C:public A{ }; . . . class F:public A{ }; Υπάρχουν και άλλες σχέσεις όπως αυτή που έχει η B με το C. Θέλω να μπορώ να κάνω: A* b = new B(); A* c = new C(); b->doSomething(*c); // error Αλλά όπως έγραψα, με τις virtual στην Α μπορώ να κάνω μόνο αυτό: A* b = new B(); C c; b->doSomething(c); Κάτι μου διαφεύγει σχετικά με τον πολυμορφισμό λογικά.
Moderators Kercyn Δημοσ. 21 Δεκεμβρίου 2016 Moderators Δημοσ. 21 Δεκεμβρίου 2016 Μπορείς να κάνεις override το doSomething εκεί που δε θες να γίνεται τίποτα και να πετάς ένα error or something. Υπάρχουν και άλλοι πιο "μαγικοί" τρόποι αλλά ο σχεδιασμός που έχεις είναι λάθος και θα πρέπει να τον ξανασκεφτείς. Από τη στιγμή που στο base class σου έχεις ένα function, τότε εκ των πραγμάτων θεωρείς ότι ό,τι υπάρχει στο base class (είτε attribute είτε λειτουργία) υπάρχει και "βγάζει νόημα" για όποιο class κληρονομήσει το base σου. 1
CookieMonster80 Δημοσ. 21 Δεκεμβρίου 2016 Μέλος Δημοσ. 21 Δεκεμβρίου 2016 Αρχικά ευχαριστώ που ασχολήθηκες. Όταν δεν υπάρχει σχέση μου αρκεί να μην γίνεται τίποτα εξού και τα άδεια body στην base. Θέλω κάθε derived να έχει την δυνατότητα να αλληλεπιδράσει με τις υπόλοιπες, άλλο που αυτό συμβαίνει για μερικές. Μπορείς να αναφέρεις τους "μαγικούς" τρόπους αλλά και γενικότερα άλλη υλοποίηση όχι με κώδικα αλλά πιο αφηρημένα ώστε να μην μου δώσεις "έτοιμο φαγητό" ;
Moderators Kercyn Δημοσ. 21 Δεκεμβρίου 2016 Moderators Δημοσ. 21 Δεκεμβρίου 2016 Δες την απάντηση εδώ.
παπι Δημοσ. 21 Δεκεμβρίου 2016 Δημοσ. 21 Δεκεμβρίου 2016 Αποτι βλεπω εχεις θεμα με το forward definition... Το οπποιο λυνεται αν γκουγλαρεις τον ορο που εγραψα, αλλα επισεις μας λεει πως εχεις κακη σχεδιαση. Σωστο θα ηταν να παιξεκσ με interface ή pure virtual classes στη c++ . 1
CookieMonster80 Δημοσ. 21 Δεκεμβρίου 2016 Μέλος Δημοσ. 21 Δεκεμβρίου 2016 Αποτι βλεπω εχεις θεμα με το forward definition... Το οπποιο λυνεται αν γκουγλαρεις τον ορο που εγραψα, αλλα επισεις μας λεει πως εχεις κακη σχεδιαση. Σωστο θα ηταν να παιξεκσ με interface ή pure virtual classes στη c++ . Ναι,προσπάθησα να είμαι συνεκτικός και άφησα απ έξω κάποιες λεπτομέρειες. Για να δουλέψει το παραπάνω απαιτείται forward definition όλων των υποκλάσεων το οποίο κάνω. Επίσης η Α είναι pure virtual. Σκέφτηκα να φτιάξω άλλη μια κλάση πχ Z η οποία υλοποιεί μόνο τις doSomething ώστε να μην προκύπτει ανάγκη για forward definition αλλά δεν νομίζω ότι καλυτερεύει την κατάσταση. Το θέμα είναι ότι δεν μπορώ ή καλύτερα δεν ξέρω πως να γίνει κάποιο downcasting από Α σε B,C,D κτλ ώστε να καλεστούν τα αντίστοιχα functions.
παπι Δημοσ. 21 Δεκεμβρίου 2016 Δημοσ. 21 Δεκεμβρίου 2016 Downcasting κανεις με dynamic, αλλα το downcasting μας λεει πως ειναι λαθος η σχεδιαση. Αυτο που λες με το z αυτο σου λεω και γω, interface.
the other one Δημοσ. 21 Δεκεμβρίου 2016 Δημοσ. 21 Δεκεμβρίου 2016 Μη τη κάνεις pure virtual. Υλοποίησέ τη ως κενή virtual και σε όποια subclass έχει νόημα την κάνεις override με τη κατάλληλη υλοποίηση. Οκ προφανώς και είναι μπακαλιά αλλά είναι ότι πιο close μπορείς να έχεις σε unified δομή. Στη θέση σου απλά θα τα έσπαγα. Το ότι είναι όλα subclass της ίδιας μαμάς δε θα πει πως ντε και καλά πρέπει να αποθηκεύοτναι στην ίδια δομή δεδομένων. Σε άλλες γλώσσες όπως στη scala ξέρω πως μπορείς να κάνεις pattern match τον τύπο οπότε απλά βάζεις το functionality που σε ενδιαφέρει σε ένα trait ( interface λαϊκιστί ) kai to καλείς από εκεί. Δε ξέρω αν υποστηρίζει και η τελευταία cpp κάτι αντίστοιχο αλλά για την ANSI δε μου ρχεται κάτι.
defacer Δημοσ. 21 Δεκεμβρίου 2016 Δημοσ. 21 Δεκεμβρίου 2016 Αυτό που καταλαβαίνω εγώ είναι ότι βασικά για οποιοδήποτε λόγο (δεν το εξετάζω αν είναι σωστό ή όχι, δεν έχουμε πληροφορίες) θέλεις στην ουσία να κάνεις μια multimethod. Συγκεκριμένα θέλεις να κάνεις double dispatch (δηλαδή, να γίνει το method call βάσει του runtime type δύο πραγμάτων: του object και της παραμέτρου της μεθόδου), που είναι βέβαια πιο εύκολο από τη γενική περίπτωση. Η τυπική λύση γι' αυτό το πρόβλημα είναι με Visitor pattern (ειδικά εφόσον αποκλείεις το dynamic_cast), τώρα που ξέρεις να γκουγκλάρεις για c++ double dispatch δε νομίζω να δυσκολευτείς. That said double dispatch και Visitor (και οι συνέπειές του) είναι advanced πράγματα και πριν μπεις στο τριπάκι θα σε συμβούλευα να είσαι 100% σίγουρος πως αυτή είναι η ενδεδειγμένη λύση για ο,τι προσπαθείς να κάνεις. 2
CookieMonster80 Δημοσ. 21 Δεκεμβρίου 2016 Μέλος Δημοσ. 21 Δεκεμβρίου 2016 @defacer: Έψαχνα από εχθές για design patterns και βρήκα το Visitor αλλά συνειδητοποίησα ότι είναι πολύ περίπλοκο για αυτό που κάνω. Οπότε εμπνεόμενος από το Visitor βρήκα την λύση η οποία ναι μεν είναι "βρώμικη" αλλά είναι καλύτερη από 100 if. Δηλαδή αυτό: class A{ virtual void doSomething(A& a) = 0; virtual void doSomething(B& {} virtual void doSomething(C& c) {} . . virtual void doSomething(F& f) {} }; class B:public A{ void doSomething(A& a){ a.doSomething(*this); } void doSomething(C& c){ cout << "B is doing something with C"; } }; class C:public A{ void doSomething(A& a){ a.doSomething(*this); } void doSomething(B& { cout << "C is doing something with B"; } }; . . . class F:public A{ }; Δηλαδή pure virtual στο base και concrete implementations στα derived που κάνουν καλούν με τον εαυτό τους την αντίστοιχη συνάρτηση της . Αλλά αυτό ναι μεν δουλεύει αλλά φαίνεται ότι για πιο πολύπλοκες ιεραρχίες κλάσεων(Ήδη έχω 7 εγώ πχ) γίνεται χαμός και είναι δύσκολο να γίνει maintain. Υπάρχει καλύτερος τρόπος έστω και πιο πολύπλοκος να στηθεί αλλά καλύτερος για scaling?
masteripper Δημοσ. 22 Δεκεμβρίου 2016 Δημοσ. 22 Δεκεμβρίου 2016 Για πολλά IF υπάρχει και η λύση του strategy pattern Βεβαια - προσωπική άποψη - καλύτερη είναι η λύση Table Oriented Programming...Μια μικρή βάση - πίνακας/ες-->Rules... Ο πίνακας κρατάει όλες τις παραμετρους εισόδου και για κάθε μοναδικό συνδυασμό βγάζει 1 αποτέλεσμα...δουλεύεις με αυτό...
BabyRage Δημοσ. 22 Δεκεμβρίου 2016 Δημοσ. 22 Δεκεμβρίου 2016 Μήπως αυτή η ερώτηση ανήκει στην περίπτωση Site: XYproblem ? Τι πρόβλημα προσπαθείς να λύσεις με αυτόν τον σχεδιασμό; 1
DevFromHell Δημοσ. 22 Δεκεμβρίου 2016 Δημοσ. 22 Δεκεμβρίου 2016 Πώ τί είναι αυτό το πράγμα.. Είδα τώρα κώδικα C++ μετά απο αρκετό καιρό και ανατρίχιασα.. και στο νήμα αυτό φαίνεται πόσο αφιλόξενη είναι αυτή η γλώσσα στην κατανόηση βασικών αρχών object-oriented σχεδίασης.. Java και πάλι Java.. Πολύ καλή όμως αυτή η απορία.. Εγώ άν είχα να αντιμετωπίσω αυτό το πρόβλημα θα έφτιαχνα ένα Factory Pattern πάντως και θα ξεχνούσα αλληλεπιδράσεις παιδιών, if-else κτλ γιατί όσο χάνεις απο πολυμορφισμό τόσο πιό περιπλοκος γίνεται ο κώδικας και τόσο πιό εύκολο να κάνεις λάθη.. Αν χρησιμοποιήσουμε virtual μεθόδους δέν παίζει και το πρόβλημα με το synchronization? Δέν θα θέλει double-checked locking για να είναι thread safe κτλ?
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα