τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Στο προηγούμενο κεφάλαιο, αναφέραμε εν συντομία ορισμένες έννοιες κλάσεων και αντικειμένων. Τώρα, ας τις εξετάσουμε μαζί.
class είναι η λέξη-κλειδί καθορισμού της κλάσης, ακολουθούμενη από το όνομα της κλάσης καθορισμού, {} είναι το κύριο σώμα της κλάσης, ακολουθούμενο από ";", οι συναρτήσεις μελών που ορίζονται στην κλάση επεκτείνονται από προεπιλογή (ενσωματωμένη)
Μορφή ενθυλάκωσης, χωρισμένη σε τρεις τύπους: δημόσιο, ιδιωτικό και προστατευμένο στο } δηλ. τάξη.
Η κλάση ορίζει ένα νέο πεδίο εφαρμογής Όλα τα μέλη της κλάσης βρίσκονται στο πεδίο εφαρμογής της κλάσης Όταν ορίζετε μέλη εκτός της κλάσης, πρέπει να χρησιμοποιήσετε τον τελεστή εμβέλειας για να υποδείξετε σε ποιον τομέα κλάσης ανήκει.
Ακολουθεί η ταινία μεγάλου μήκους///
• Η διαδικασία δημιουργίας ενός αντικειμένου στη φυσική μνήμη χρησιμοποιώντας έναν τύπο κλάσης ονομάζεται δημιουργία κλάσης.
• Μια κλάση είναι μια αφηρημένη περιγραφή ενός αντικειμένου. Είναι σαν ένα μοντέλο
Είναι μια δήλωση και δεν εκχωρείται χώρος μόνο όταν ένα αντικείμενο δημιουργείται χρησιμοποιώντας μια κλάση.
• Μια κλάση μπορεί να δημιουργήσει στιγμιότυπα πολλαπλών αντικειμένων.
Για να το συνοψίσουμε σε μια φράση: μόνο όταν τα αντικείμενα είναι στιγμιότυπα με κλάσεις θα κατανέμουν χώρο (όπως ακριβώς η κατασκευή ενός σπιτιού με σχέδια θα καταλάβει χώρο).
- class Date
- {
- public:
- void Init(int year, int month, int day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- void Print()
- {
- cout << _year << "/" << _month << "/" << _day << endl;
- }
- private:
- // 这⾥只是声明,没有开空间
- int _year;
- int _month;
- int _day;
- };
Στον παραπάνω κώδικα, οι μεταβλητές μέλους είναι μόνο καθορισμένες και δεν ανοίγει νέος χώρος και
- // Date类实例化出对象d1和d2
- Date d1;
- Date d2;
Δημιουργούνται δύο νέα αντικείμενα, οπότε ανοίγεται ένας νέος χώρος.
• Το πρώτο μέλος βρίσκεται στη μετατόπιση διεύθυνσης 0 από τη δομή.
• Άλλες μεταβλητές μελών θα πρέπει να αντιστοιχίζονται σε διευθύνσεις που είναι ακέραια πολλαπλάσια ενός συγκεκριμένου αριθμού (λογάριθμος).
• Σημείωση: λογάριθμος = ο μικρότερος από τον προεπιλεγμένο λογάριθμο του μεταγλωττιστή και το μέγεθος του μέλους.
• Ο προεπιλεγμένος λογάριθμος στο VS είναι 8
• Το συνολικό μέγεθος της δομής είναι: ένα ακέραιο πολλαπλάσιο του μέγιστου αριθμού κατά ζεύγη (ο μεγαλύτερος από όλους τους τύπους μεταβλητών και η μικρότερη προεπιλεγμένη παράμετρος ζεύξης).
• Εάν μια δομή είναι ένθετη, η ένθετη δομή ευθυγραμμίζεται με ένα ακέραιο πολλαπλάσιο του μέγιστου λογαρίθμου της και του συνολικού μεγέθους της δομής
Είναι ένα ακέραιο πολλαπλάσιο όλων των μεγαλύτερων λογαρίθμων (συμπεριλαμβανομένων των λογαρίθμων ένθετων δομών).
Αυτό είναι αυτό που γνωρίζουμε στη γλώσσα C Πάρτε ως παράδειγμα τις ακόλουθες ερωτήσεις:
- // 计算⼀下A实例化的对象是多⼤?
- class A
- {
- public:
- void Print()
- {
- cout << _ch << endl;
- }
- private:
- char _ch;
- int _i;
- };
Δεν υπάρχει καμία συνάρτηση που ονομάζεται, οπότε απλά κοιτάξτε τις μεταβλητές του μέλους _ch είναι ένας τύπος χαρακτήρων, με μέγεθος 1 byte, με μέγεθος 4 byte αριθμός στοίχισης, άρα είναι _ Τοποθετήστε το ch στη θέση με δείκτη 0, αφήστε τρία κενά και μετά βάλτε _i Καταλαμβάνει συνολικά 8 byte χώρου από το 0 έως το 7, που είναι ακέραιο πολλαπλάσιο του μέγιστου αριθμού στοίχισης. Πληροί τις προϋποθέσεις, επομένως η απάντηση σε αυτή την ερώτηση είναι 8 .
Και τι γίνεται αν είναι αυτές οι δύο ερωτήσεις;
- class B
- {
- public:
- void Print()
- {
- //...
- }
- };
-
- class C
- {
- };
Μπορούμε να βρούμε ότι υπάρχει μια κενή συνάρτηση στην κλάση Β και κανένα μέλος στην κλάση C. Στη γλώσσα C, κάνουμε και τις δύο κλάσεις να καταλαμβάνουν 1 byte χώρου.
• ρεΥπάρχουν δύο συναρτήσεις μέλους, Init και Print, στην κατηγορία ate Δεν υπάρχει διάκριση μεταξύ διαφορετικών αντικειμένων στο σώμα της συνάρτησης Τότε όταν το d1 καλεί Init και Print
Κατά την εκτύπωση της συνάρτησης, πώς γνωρίζει η συνάρτηση εάν πρέπει να έχει πρόσβαση στο αντικείμενο d1 ή στο αντικείμενο d2;Τότε εδώ θα δούμε ότι η C++ δίνει
Ένας σιωπηρός δείκτης αυτός λύνει το πρόβλημα εδώ
• Μετά τη μεταγλώττιση του μεταγλωττιστή, οι συναρτήσεις μέλους της κλάσης θα προσθέσουν έναν δείκτη του τρέχοντος τύπου κλάσης, που ονομάζεται αυτός ο δείκτης, στην πρώτη θέση της επίσημης παραμέτρου από προεπιλογή. Για παράδειγμα, το πραγματικό πρωτότυπο της κλάσης Init of Date είναι, void Init(Date* const this, int year,
int μήνα, int ημέρα)
• Κατά την πρόσβαση σε μεταβλητές μέλους στις συναρτήσεις μέλους μιας κλάσης, γίνεται ουσιαστικά πρόσβαση σε αυτές μέσω του δείκτη αυτού. Για παράδειγμα, όταν εκχωρείτε μια τιμή στο _year στη συνάρτηση Init, αυτό-.
>_έτος = έτος;
• Η C++ ορίζει ότι αυτός ο δείκτης δεν μπορεί να γραφτεί ρητά στη θέση των πραγματικών παραμέτρων και των τυπικών παραμέτρων (ο μεταγλωττιστής θα το χειριστεί αυτό κατά τη μεταγλώττιση), αλλά αυτός ο δείκτης μπορεί να χρησιμοποιηθεί ρητά στο σώμα της συνάρτησης.
για παράδειγμα
- class Date
- {
- public:
- // void Init(Date* const this, int year, int month, int day)
- void Init(int year, int month, int day)
- {
- // 编译报错:error C2106: “=”: 左操作数必须为左值
- // this = nullptr;
- // this->_year = year;
- _year = year;
- this->_month = month;
- this->_day = day;
- }
- void Print()
- {
- cout << _year << "/" << _month << "/" << _day << endl;
- }
- private:
- // 这⾥只是声明,没有开空间
- int _year;
- int _month;
- int _day;
- };
-
- int main()
- {
- // Date类实例化出对象d1和d2
- Date d1;
- Date d2;
- // d1.Init(&d1, 2024, 3, 31);this指针
- d1.Init(2024, 3, 31);
-
- // d1.Init(&d2, 2024, 7, 5);
- d2.Init(2024, 7, 5);
- //不能自己写
- return 0;
- }
Για την εγγραφή των πραγματικών παραμέτρων στη συνάρτηση Init, η C++ θα προσθέσει μια αόρατη σταθερά αυτόν τον δείκτη (που δεν μπορεί να τροποποιηθεί) στην πρώτη μεταβλητή της συνάρτησης, όπως φαίνεται στα σχόλια της συνάρτησης.
Εφόσον ο μηδενικός δείκτης δεν έχει αποαναφερθεί, δεν θα αναφέρεται κανένα σφάλμα.
- class A
- {
- public:
- void Print()
- {
- cout << "A::Print()" << endl;
- }
- private:
- int _a;
- };
-
- int main()
- {
- A* p = nullptr;
- p->Print();
- return 0;
- }
Αν και στο p έχει εκχωρηθεί ένας μηδενικός δείκτης και δείχνει στη συνάρτηση Εκτύπωση, δεν παραπέμπεται, επομένως δεν θα αναφερθεί κανένα σφάλμα και αυτό το πρόγραμμα:
- class A
- {
- public:
- void Print()
- {
- cout << "A::Print()" << endl;
- cout << _a << endl;//这个地方多了一句
- }
- private:
- int _a;
- };
-
- int main()
- {
- A* p = nullptr;
- p->Print();
- return 0;
- }
Σε σύγκριση με το προηγούμενο πρόγραμμα, υπάρχει μόνο μία ακόμη πρόταση cout << _a << endl, αλλά αυτή τη στιγμή ο μηδενικός δείκτης δείχνει σε μια μεταβλητή μέλος και ο μηδενικός δείκτης θα αποαναφερθεί, επομένως το πρόγραμμα θα αναφέρει ένα σφάλμα.
Η προεπιλεγμένη συνάρτηση μέλους είναι μια συνάρτηση μέλους που δεν υλοποιείται ρητά από τον χρήστη και δημιουργείται αυτόματα από τον μεταγλωττιστή. Για μια κλάση, αν δεν τη γράψουμε, ο μεταγλωττιστής θα δημιουργήσει τις ακόλουθες 6 προεπιλεγμένες συναρτήσεις μελών από προεπιλογή, οι οποίες είναι οι ακόλουθες 6
Ο κατασκευαστής είναι μια ειδική συνάρτηση μέλους Θα πρέπει να σημειωθεί ότι παρόλο που το όνομα του κατασκευαστή ονομάζεται κατασκευαστής, το κύριο καθήκον του κατασκευαστή δεν είναι να ανοίξει χώρο για να δημιουργήσει αντικείμενα (το τοπικό αντικείμενο που χρησιμοποιούμε συχνά είναι ο χώρος όταν η στοίβα. δημιουργείται πλαίσιο) ), αντ 'αυτού το αντικείμενο αρχικοποιείται όταν το αντικείμενο είναι στιγμιότυπο. Η ουσία είναι να αντικαταστήσετε τη συνάρτηση Init αρχικοποίησης.
1. Το όνομα της συνάρτησης είναι το ίδιο με το όνομα της κλάσης.
2. Καμία τιμή επιστροφής. (Δεν χρειάζεται να γράψετε κενό)
3. Όταν το αντικείμενο είναι στιγμιότυπο, το σύστημα θα καλέσει αυτόματα τον αντίστοιχο κατασκευαστή.
4. Οι κατασκευαστές μπορεί να υπερφορτωθούν.
5. Εάν δεν υπάρχει ρητά καθορισμένος κατασκευαστής στην κλάση, ο μεταγλωττιστής C++ θα δημιουργήσει αυτόματα έναν προεπιλεγμένο κατασκευαστή χωρίς παραμέτρους Μόλις ο χρήστης τον ορίσει ρητά, ο μεταγλωττιστής δεν θα τον δημιουργεί πλέον.
Τα πρώτα πέντε στοιχεία είναι σχετικά απλά, ας δώσουμε ένα παράδειγμα:
- class Date
- {
- public:
- //1.⽆参构造函数,无需写void
- Date()//若不写,则构造函数会写出这一中无参构造函数
- {
- _year = 1;
- _month = 1;
- _day = 1;
- }
- //2.全缺省构造函数
- Date(int year = 1, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year;
- int _month;
- int _day;
- }
-
- int main()
- {
- Date d1;//此时相当于已经自动调用了Init函数
- Date d2;
-
- return 0;
- }
Δύο κατασκευαστές είναι γραμμένοι στο πρόγραμμα, ο ένας είναι κατασκευαστής χωρίς παραμέτρους και ο άλλος είναι ένας πλήρης προεπιλεγμένος κατασκευαστής, το πρόγραμμα θα γράψει έως και έναν κατασκευαστή χωρίς παραμέτρους δύο συναρτήσεις είναι υπερφορτωμένες συναρτήσεις, λόγω της ασάφειας κλήσης, οι δύο συναρτήσεις δεν μπορούν να υπάρχουν ταυτόχρονα.
6. Οι κατασκευαστές χωρίς παραμέτρους, οι πλήρεις προεπιλεγμένες κατασκευαστές και οι κατασκευαστές που δημιουργούνται από τον μεταγλωττιστή από προεπιλογή όταν δεν γράφουμε έναν κατασκευαστή ονομάζονται όλοι προεπιλεγμένοι κατασκευαστές. Ωστόσο, μία και μόνο μία από αυτές τις τρεις συναρτήσεις υπάρχει και δεν μπορεί να υπάρχει ταυτόχρονα. Αν και ο κατασκευαστής χωρίς παραμέτρους και ο πλήρης προεπιλεγμένος κατασκευαστής συνιστούν υπερφόρτωση συναρτήσεων, θα υπάρχει ασάφεια κατά την κλήση τους. Θα πρέπει να σημειωθεί ότι πολλοί μαθητές πιστεύουν ότι ο προεπιλεγμένος κατασκευαστής είναι ο προεπιλεγμένος κατασκευαστής που δημιουργείται από τον μεταγλωττιστή Ονομάζεται προεπιλεγμένη κατασκευή.
Το έκτο χαρακτηριστικό είναι πιο περίπλοκο: ο κατασκευαστής χωρίς παραμέτρους, ο πλήρης προεπιλεγμένος κατασκευαστής και ο κατασκευαστής που δημιουργείται από τον μεταγλωττιστή από προεπιλογή όταν δεν γράφουμε έναν κατασκευαστή ονομάζονται όλοι προεπιλεγμένοι κατασκευαστές και μπορεί να υπάρχει μόνο ένας κατασκευαστής προεπιλεγμένος κατασκευαστής ως ο κατασκευαστής που δημιουργείται από τον μεταγλωττιστή από προεπιλογή!
7. Εάν δεν το γράψουμε, ο κατασκευαστής που δημιουργείται από τον μεταγλωττιστή από προεπιλογή δεν έχει απαιτήσεις για την προετοιμασία των ενσωματωμένων μεταβλητών μελών. Με άλλα λόγια, το αν είναι αρχικοποιημένο ή όχι είναι αβέβαιο, εξαρτάται από τον μεταγλωττιστή . Για μεταβλητές μέλους προσαρμοσμένου τύπου, απαιτείται να καλέσετε τον προεπιλεγμένο κατασκευαστή αυτής της μεταβλητής μέλους για να την αρχικοποιήσετε. Εάν αυτή η μεταβλητή μέλους δεν έχει προεπιλεγμένο κατασκευαστή, θα αναφερθεί ένα σφάλμα .
Η λειτουργία του καταστροφέα είναι αντίθετη με αυτή του κατασκευαστή Ο καταστροφέας δεν ολοκληρώνει την καταστροφή του ίδιου του αντικειμένου. Για παράδειγμα, το τοπικό αντικείμενο έχει ένα πλαίσιο στοίβας Δεν χρειάζεται να το ελέγξουμε η C++ ορίζει ότι τα αντικείμενα όταν καταστραφούν, ο καταστροφέας θα κληθεί αυτόματα να ολοκληρώσει την εκκαθάριση και την απελευθέρωση των πόρων στο αντικείμενο. Η λειτουργία του καταστροφέα είναι παρόμοια με τη συνάρτηση Destroy που εφαρμόσαμε πριν στο Stack Ο καταστροφέας είναι ακριβώς όπως η συνάρτηση Destroy Θα πρέπει να χρησιμοποιείται για δομές δεδομένων που απαιτούν μη τοπικά αντικείμενα όπως στοίβες και ουρές για να υποβάλουν αίτηση για πόρους.
1. Το όνομα του καταστροφέα προηγείται από τον χαρακτήρα ~ πριν από το όνομα της κλάσης. (Παρόμοιο με την άρνηση bitwise στη γλώσσα C)
2. Καμία παράμετρος και καμία τιμή επιστροφής. (Αυτό είναι παρόμοιο με τη δομή και δεν χρειάζεται να προσθέσετε κενό)
3. Μια τάξη μπορεί να έχει μόνο έναν καταστροφέα. Εάν δεν ορίζεται ρητά, το σύστημα θα δημιουργήσει αυτόματα έναν προεπιλεγμένο καταστροφέα.
4. Όταν τελειώσει ο κύκλος ζωής του αντικειμένου, το σύστημα θα καλέσει αυτόματα τον καταστροφέα.
5. Παρόμοια με τον κατασκευαστή, εάν δεν γράψουμε έναν καταστροφέα που δημιουργείται αυτόματα από τον μεταγλωττιστή, δεν θα επεξεργαστεί τα μέλη του ενσωματωμένου τύπου θα καλέσουν τους καταστροφείς τους.
6. Θα πρέπει επίσης να σημειωθεί ότι όταν γράφουμε ρητά τον καταστροφέα, θα καλείται και ο καταστροφέας του μέλους προσαρμοσμένου τύπου, δηλαδή θα καλείται αυτόματα ο καταστροφέας του μέλους προσαρμοσμένου τύπου, ανεξάρτητα από την κατάσταση.
7. Εάν δεν υπάρχουν πόροι που ζητούνται στην κλάση, ο καταστροφέας δεν χρειάζεται να γραφτεί και ο προεπιλεγμένος καταστροφέας που δημιουργείται από τον μεταγλωττιστή μπορεί να χρησιμοποιηθεί απευθείας, όπως Date, εάν μπορεί να χρησιμοποιηθεί ο προεπιλεγμένος καταστροφέας Δεν χρειάζεται να το εμφανίσετε, όπως το MyQueue, αλλά όταν υπάρχει μια εφαρμογή πόρων, πρέπει να γράψετε μόνοι σας τον καταστροφέα, διαφορετικά θα προκαλέσει διαρροή πόρων, όπως το Stack.
8. Για πολλά αντικείμενα σε έναν τοπικό τομέα, η C++ ορίζει ότι αυτά που ορίζονται αργότερα θα καταστραφούν πρώτα.
Όπως και στον παραπάνω κατασκευαστή, ο προεπιλεγμένος καταστροφέας που δημιουργείται αυτόματα από τη C++ γενικά δεν θα μας βοηθήσει πολύ, αλλά είναι πιο βολικό σε ορισμένες σπάνιες περιπτώσεις, όπως η χρήση δύο στοίβων για την υλοποίηση μιας ουράς:
- public:
- Stack(int n = 4)//相当于Init
- {
- _a = (STDataType*)malloc(sizeof(STDataType) * n);
- if (nullptr == _a)
- {
- perror("malloc fail!");
- return;
- }
- _capacity = n;
- _top = 0;
- }
- ~Stack()//相当于Destroy
- {
- cout << "~Stack()" << endl;
- free(_a);
- _a = nullptr;
- _top = _capacity = 0;
- }
- private:
- STDataType* _a;
- size_t _capacity;
- size_t _top;
- };
-
- class MyQueue
- {
- public:
- //编译器默认⽣成MyQueue的析构函数调⽤了Stack的析构,释放的Stack内部的资源
- // 显⽰写析构,也会⾃动调⽤Stack的析构
-
- private:
- Stack pushst;
- Stack popst;
- };
Αυτή τη στιγμή, ο μεταγλωττιστής στο MyQueue καλεί αυτόματα τον κατασκευαστή (αρχικοποίηση) και τον καταστροφέα (καταστροφή) της στοίβας.