Προγραμματισμός Υπολογιστών με C++ ( 2012-13 ) 12η διάλεξη Ίων Ανδρουτσόπουλος http://www.aueb.gr/users/ion/ 1
Τι θα ακούσετε σήμερα Τροποποίηση μεθόδων σε παράγωγες τάξεις. Κατασκευαστές παραγώγων τάξεων. Ενσωμάτωση αντικειμένων μιας τάξης σε αντικείμενα άλλων τάξεων. Περισσότερα για μεθόδους που επιστρέφουν αναφορές. 2
Παράδειγμα βασικής τάξης class Point { int x, y; public: void setx(int newx) { x = newx; void sety(int newy) { y = newy; int getx() const { return x; int gety() const { return y; void display() const { cout << "x: " << x << ", y: " << y << endl; Point(int newx = 0, int newy = 0): x(newx), y(newy) { Point(const Point& original): x(original.x), y(original.y) { ; int main() { Point p1(1, 2); p1.display(); 3
Παράδειγμα παράγωγης τάξης class LabeledPoint : public Point { // Παράγωγη τάξη της Point. string label; // Πρόσθετη μεταβλητή-μέλος. public: // Νέες μέθοδοι: void setlabel(const string& newlabel) { label = newlabel; string getlabel() const { return label; LabeledPoint(int newx = 0, int newy = 0, // Κατασκευαστής. const string& newlabel = "label"); ; int main() { LabeledPoint p2(1, 2, "test"); p2.setx(3); p2.sety(4); // Κληρονομημένες μέθοδοι. p2.setlabel("other"); // Πρόσθετη μέθοδος. cout << p2.getlabel() << endl; // Τυπώνει «other». p2.display(); // Κληρονομημένη. Δεν τυπώνει όμως το label. 4
Τροποποίηση μεθόδου class LabeledPoint : public Point { string label; public: void setlabel(const string& newlabel) { label = newlabel; string getlabel() const { return label; LabeledPoint(int newx = 0, int newy = 0, const string& newlabel = "label"); void display() const; // Τροποποίηση μεθόδου. (. Point (Υπάρχει και στην // ; // Τώρα τυπώνεται και το label: void LabeledPoint::display() const { cout << "label: " << label << ", "; // cout << x << y; // Λάθος. Ιδιωτικά μέλη της Point. // cout << getx() << gety(); // ΟΚ, αλλά καλύτερα το ακόλουθο: Point::display(); // Κλήση της αρχικής μορφής της μεθόδου. 5
Κατασκευαστής παράγωγης τάξης LabeledPoint::LabeledPoint(int newx, int newy, const string& newlabel) : Point(newX, newy), // Κλήση του κατασκευαστή της Point. label(newlabel) // Αρχικοποίηση μεταβλητής. { // x = NewX; // Λάθος. Δεν έχουμε πρόσβαση στα ιδιωτικά μέλη // της Point. Κατά τη δημιουργία ενός αντικειμένου της παράγωγης τάξης, καλείται πρώτα ο κατασκευαστής της βασικής τάξης. Εάν ο κατασκευαστής της παράγωγης τάξης δεν περιέχει ρητή κλήση κατασκευαστή της βασικής, καλείται ο προεπιλεγμένος κατασκευαστής της βασικής τάξης. Στο συγκεκριμένο παράδειγμα, χωρίς ρητή κλήση κατασκευαστή της Point, όλα τα αντικείμενα LabeledPoint θα είχαν x = 0, y = 0. 6
Χρήση της Point σε άλλη τάξη class Line { Point start, end; string label; public: Line(int x1, int y1, int x2, int y2, const string& s) : start(x1, y1), end(x2, y2), label(s) { void display() const { cout << label << endl; start.display(); end.display(); ; int main() { Line myline(10, 20, 40, 50, "test"); myline.display(); 7
Σχέσεις is-a και has-a Η κληρονομικότητα δεν είναι ο μόνος τρόπος να επαναχρησιμοποιήσουμε μια υπάρχουσα τάξη. Η κληρονομικότητα αντιστοιχεί σε σχέσεις is-a. Ένα αντικείμενο LabeledPoint είναι ένα είδος Point. Ένα αυτοκίνητο είναι ένα είδος οχήματος. Συχνά μας χρειάζονται σχέσεις has-a (ή part-of). Ένα αντικείμενο Line περιέχει δύο αντικείμενα Point. Ένα αυτοκίνητο έχει τέσσερις ρόδες. 8
Η βασική τάξη Person class Person { string name; unsigned short numaddresses; string* addresses; public: Person(const string& namein, unsigned short numaddressesin, const string addressesin[]); Person(const Person& original); ~Person() { delete []addresses; Person& operator=(const Person& right); // Επιστρέφουν αναφορά στο όνομα ή τη διεύθυνση που υπάρχει // στο εσωτερικό του αντικειμένου. Μπορούν να χρησιμοποιηθούν // και για να αλλάξουμε το όνομα ή τη διεύθυνση μέσα στο αντικείμενο: string& getname() { return name; string& getaddress(unsigned i) { return addresses[i]; ; 9
Παράδειγμα χρήσης της Person int main() { string addr[] = {"Πατησίων 76", "Κοδριγκτώνος 10"; Person p("γιώργος", 2, addr); cout << p.getname() << endl << p.getaddress(0) << endl << p.getaddress(1) << endl; p.getname() = "Γεώργιος"; // Αλλαγή ονόματος. p.getaddress(1) = "Κοδριγκτώνος 12"; // Αλλαγή διεύθ/σης. cout << p.getname() << endl << p.getaddress(0) << endl << p.getaddress(1) << endl; 10
Κατασκευαστής της Person Person::Person(const string& namein, unsigned short numaddressesin, const string addressesin[]) : name(namein), numaddresses(numaddressesin), addresses(new string[numaddresses]) { for(unsigned short i = 0; i < numaddresses; i++) { addresses[i] = addressesin[i]; Person::Person(const Person& original) : name(original.name), numaddresses(original.numaddresses), addresses(new string[numaddresses]) { for(unsigned short i = 0; i < numaddresses; i++) { addresses[i] = original.addresses[i]; 11
Τελεστής εκχώρησης της Person Person& Person::operator=(const Person& right) { if(this = = &right) return *this; name = right.name; if(numaddresses!= right.numaddresses) { delete []addresses; numaddresses = right.numaddresses; addresses = new string[numaddresses]; for(unsigned short i = 0; i < numaddresses; i++) { addresses[i] = right.addresses[i]; return *this; 12