Berbagi teknologi

Dasar-Dasar C (2)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Daftar isi

1. Kelas dan Objek

1.1 Definisi kelas

1.2 Akses kualifikasi

1.3 Domain kelas

2. Instansiasi

2.1 Konsep Instansiasi

2.2 Ukuran benda

3. penunjuk ini

4.Fungsi anggota kelas default

4.1Konstruktor

4.2 Destruktor

4.5 Kelebihan beban operator


1. Kelas dan Objek

1.1 Definisi kelas

Format definisi kelas

class adalah kata kunci yang mendefinisikan kelas, Stack adalah nama kelas, dan {} adalah isi kelas. Perhatikan bahwa titik koma di akhir definisi tidak dihilangkan. Isi badan kelas disebut anggota kelas: variabel dalam kelas disebut atribut atau variabel anggota fungsi kelas dalam kelas disebut metode atau fungsi anggota kelas;

  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. class Stack
  5. {
  6. //成员变量
  7. int* a;
  8. int top;
  9. int capacity;
  10. //成员函数
  11. void Push()
  12. {
  13. }
  14. void Pop()
  15. {
  16. }
  17. };//分号不能省略
  18. int main()
  19. {
  20. return 0;
  21. }

  • Untuk membedakan variabel anggota, biasanya ditambahkan pengenal khusus pada variabel anggota, seperti dimulai dengan _ atau m_ sebelum atau sesudah variabel anggota.Tidak ada peraturan mengenai sintaks C++ ini, ini hanya masalah preferensi pribadi atau perusahaan.
  1. //为区分成员变量,一般前面加_
  2. //成员变量
  3. int* _a;
  4. int _top;
  5. int _capacity;
  • Struct di C++ juga dapat mendefinisikan kelas. C++ kompatibel dengan penggunaan struct di C. Pada saat yang sama, struct telah ditingkatkan menjadi kelas. Perubahan yang jelas adalah fungsi juga dapat didefinisikan dalam struct tetap merekomendasikan penggunaan kelas untuk mendefinisikan kelas.

  • Anggota yang ditentukan dalam kelas default adalah inline

1.2 Akses kualifikasi

C++ adalah cara untuk mengimplementasikan enkapsulasi, menggunakan kelas untuk menggabungkan properti dan metode suatu objek untuk membuat objek lebih lengkap, dan secara selektif menyediakan antarmukanya kepada pengguna eksternal melalui hak akses.

  • Anggota yang dimodifikasi oleh publik (publik) dapat langsung diakses di luar kelas, anggota yang dimodifikasi oleh dilindungi (dilindungi) dan pribadi (pribadi) tidak dapat langsung diakses di luar kelas, dilindungi dan pribadi adalah sama
  • Cakupan izin akses dimulai dari posisi munculnya izin akses hingga muncul qualifier akses berikutnya. Jika tidak ada qualifier akses berikutnya, cakupan berakhir di } yang merupakan akhir dari kelas.
  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. class Stack
  5. {
  6. ///
  7. void Push()
  8. {
  9. }
  10. //Push 没给限定符 class默认私有 private
  11. ///
  12. public:
  13. void Pop()
  14. {
  15. }
  16. int Swap()
  17. {
  18. }
  19. //Pop和Swap 被public修饰,直到下一个限定符出现之前都为公有
  20. ///
  21. protected:
  22. int add();
  23. //add 被public修饰,直到下一个限定符出现之前都为保护
  24. /// /
  25. private:
  26. int* _a;
  27. int _top;
  28. int _capacity;
  29. //成员变量被private修饰,直到}结束都为私有
  30. };
  31. int main()
  32. {
  33. Stack st;
  34. //公有可以访问
  35. st.Pop();
  36. st.Swap();
  37. //私有不可访问
  38. st._top;
  39. return 0;
  40. }

Catatan tambahan:

  1. Ketika anggota definisi kelas tidak diubah oleh kualifikasi akses, mereka default ke privat, dan struct default ke publik.
  2. Secara umum, variabel anggota akan dibatasi pada pribadi/dilindungi, dan fungsi anggota yang perlu digunakan oleh orang lain akan ditempatkan sebagai publik.

1.3 Domain kelas

Kelas mendefinisikan cakupan baru. Semua anggota kelas berada dalam cakupan kelas. Saat mendefinisikan anggota di luar kelas, Anda perlu menggunakan operator ::scope untuk menunjukkan cakupan kelas mana yang dimiliki anggota tersebut.

Domain kelas mempengaruhi aturan pencarian kompilasi. Jika Init dalam program berikut tidak menentukan domain kelas Stack, kompiler akan memperlakukan Init sebagai fungsi global. Jika tidak dapat menemukan anggota seperti _top selama kompilasi, ia akan menuju ke domain kelas untuk menemukannya.

  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. class Stack
  5. {
  6. public:
  7. void Init(int x, int y);
  8. };
  9. void Stack::Init(int x, int y)
  10. {
  11. _top = x;
  12. _capacity = y;
  13. }
  14. int main()
  15. {
  16. return 0;
  17. }

Melihat:

  1. Deklarasi fungsi dan definisi di kelas dipisahkan. Setelah kelas dibuat, domain kelas baru harus ditentukan, jika tidak maka domain kelas tidak dapat diakses.

2. Instansiasi

2.1 Konsep Instansiasi

  • Proses pembuatan suatu tipe dalam memori fisik disebut instantiasi kelas.
  • Kelas adalah deskripsi abstrak dari suatu objek. Itu seperti model. Ini membatasi variabel anggota kelas. Variabel anggota ini hanya dideklarasikan dan tidak ada ruang yang dialokasikan ketika suatu objek dipakai dengan kelas.

  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. class Stack
  5. {
  6. //声明
  7. int* _a;
  8. int _top;
  9. int _capacity;
  10. };
  11. int main()
  12. {
  13. Stack::_top = 2024;
  14. //编译器报错,_top只是声明,并未实例化
  15. return 0;
  16. }
  • Sebuah kelas dapat membuat instance beberapa objek, dan objek yang dibuat tersebut menempati ruang fisik aktual dan menyimpan variabel anggota. Misal: membuat instance objek dari suatu kelas seperti menggunakan gambar desain arsitektur untuk membangun rumah di dunia nyata. Kelas itu seperti gambar desain yang merencanakan jumlah ruangan, ukuran rumah, dan lain-lain, tetapi tidak ada fisiknya bangunan, dan tidak dapat ditinggali oleh manusia, hanya jika rumah dibangun dengan menggunakan gambar desain barulah orang dapat tinggal di dalam rumah tersebut.Kelas yang sama seperti gambar desain. Ia hanya memberi tahu kompiler berapa banyak memori yang akan dibuka, tetapi tidak membuka memori hanya objek yang dipakai yang dialokasikan memori fisik untuk menyimpan data.
    1. //text.cpp
    2. #include<iostream>
    3. using namespace std;
    4. class Stack
    5. {
    6. //声明
    7. int* _a;
    8. int _top;
    9. int _capacity;
    10. };
    11. int main()
    12. {
    13. Stack st;
    14. st._top=2024;
    15. //Stack实例化出st,系统已经给st分配内存了,可以存储数据,编译通过
    16. return 0;
    17. }

    2.2 Ukuran benda

  • Analisis anggota apa yang dimiliki objek kelas? Setiap objek yang dipakai oleh suatu kelas memiliki ruang data independen, sehingga objek tersebut harus berisi variabel anggota. Jadi, apakah fungsi anggota disertakan? Pertama, setelah fungsi dikompilasi, itu adalah bagian dari instruksi, yang tidak dapat disimpan dalam objek. Instruksi ini disimpan di area terpisah (segmen kode). fungsi anggota. Apakah perlu menyimpan pointer di objek? Tanggal membuat instance dua objek d1 dan d2. Baik di dan d2 memiliki variabel anggota independen _year/_month/_day untuk menyimpan datanya sendiri, tetapi fungsi anggota Init dari d1 dan d2 Pointer /Print adalah sama, dan sia-sia jika disimpan di dalam benda. Jika Anda menggunakan Date untuk membuat instance 100 objek, maka penunjuk fungsi anggota akan disimpan berulang kali sebanyak 100 kali, yang terlalu boros. Faktanya, penunjuk fungsi tidak perlu disimpan. Penunjuk fungsi adalah sebuah alamat. Fungsi pemanggil dikompilasi menjadi instruksi perakitan [alamat panggilan]. Faktanya, kompiler harus menemukan alamat fungsi tersebut saat mengkompilasi dan menghubungkan . Itu tidak ditemukan saat runtime. Ini hanya dapat ditemukan secara dinamis. Status ditemukan saat runtime, sehingga alamat fungsi perlu disimpan.

Aturan penyelarasan memori

  • Anggota pertama berada pada alamat offset 0 dari struktur
  • Variabel anggota lainnya harus disejajarkan pada alamat yang merupakan kelipatan dari nomor penyelarasan.
  • Nomor penyelarasan = Semakin kecil nomor penyelarasan default kompiler dan ukuran anggota
  • Nomor penyelarasan default platform VS x64 adalah 4, dan nomor penyelarasan default x86 adalah 8
  • Ukuran total struktur adalah: kelipatan bilangan bulat dari bilangan penyelarasan maksimum (yang terbesar dari semua variabel tipe dan bilangan penyelarasan default terkecil)
  • Jika struktur disarangkan, maka struktur yang disarangkan akan disejajarkan dengan kelipatan bilangan bulat dari bilangan penyelarasan maksimumnya, dan ukuran keseluruhan struktur adalah kelipatan bilangan bulat dari semua bilangan penyelarasan maksimum (termasuk jumlah penyelarasan struktur yang disarangkan)
  1. class A
  2. {
  3. public:
  4. void Print()
  5. {
  6. cout << _ch << endl;
  7. }
  8. private:
  9. char _ch;
  10. int _i;
  11. };
  12. //_ch 是一个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存在_ch
  13. // _i是4个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存储_i
  14. class B
  15. {
  16. public:
  17. void Print()
  18. {
  19. //。。。
  20. }
  21. };
  22. class B
  23. {
  24. };
  25. //B和C里面没有存储任何成员变量,只有一个函数,可成员函数不存对象里面
  26. // 按理来说是0,但是结构体怎么会没大小,为表示对象存在C++对这种规定大小为1,为了占位标识对象存在

3. penunjuk ini

Setelah kompiler dikompilasi, fungsi anggota kelas akan menambahkan pointer ke kelas saat ini di posisi pertama parameter formal secara default, yang disebut pointer ini.

Misalnya, prototipe Init di kelas Tanggal adalah void Init (Tanggal * const ini, int tahun, int bulan, int hari). Saat mengakses variabel anggota di fungsi anggota kelas, esensi diakses melalui penunjuk ini, seperti _tahun dalam fungsi Init, ini-&gt;_tahun=tahun

prototipe:

  1. class Date
  2. {
  3. void Print()
  4. {
  5. cout << _year << "n" << _month << "n" << _day << endl;
  6. }
  7. void Init( int year, int month,int day)
  8. {
  9. _year = year;
  10. _month = month;
  11. _day = day;
  12. }
  13. private:
  14. int _year;
  15. int _month;
  16. int _day;
  17. };

  1. Date d1;
  2. d1.Init(2024,7,10);
  3. d1.Print();
  4. Date d2;
  5. d2.Init(2024, 7, 9);
  6. d2.Print();

prototipe nyata

  1. class Date
  2. {
  3. void Init(Date* const this,int year, int month,int day)
  4. {
  5. this->_year = year;
  6. this->_month = month;
  7. this->_day = day;
  8. }
  9. void Printf(Date* const this)
  10. {
  11. cout << this->_year << "n" <<this-> _month << "n" << this->_day << endl;
  12. }
  13. private:
  14. int _year;
  15. int _month;
  16. int _day;
  17. };

  1. Date d1;
  2. d1.Init(&d1,2024,7,10);
  3. d1.Print(&d1);
  4. Date d2;
  5. d2.Init(&d2,2024, 7, 9);
  6. d2.Print();

C++ menetapkan bahwa tidak diperbolehkan untuk menulis pointer ini pada posisi parameter aktual dan parameter formal (kompiler akan menanganinya saat kompilasi), tetapi pointer ini dapat digunakan secara eksplisit di badan fungsi konten yang ditunjuk oleh penunjuk ini bisa

penunjuk ini disimpan di tumpukan

4.Fungsi anggota kelas default

Fungsi anggota default adalah fungsi anggota yang tidak ditentukan secara eksplisit oleh pengguna dan secara otomatis dihasilkan oleh kompiler.

4.1Konstruktor

Konstruktor adalah fungsi anggota khusus. Perlu dicatat bahwa meskipun konstruktor disebut konstruktor, isi utama konstruktor bukanlah membuka ruang untuk membuat objek (objek lokal yang biasa kita gunakan adalah ruang yang dibuka ketika bingkai tumpukan dibuat) ), tetapi objek diinisialisasi saat objek dipakai. Inti dari konstruktor adalah menggantikan fungsi fungsi Init yang kita tulis di kelas Stack dan Date sebelumnya. Pemanggilan otomatis konstruktor dengan sempurna menggantikan fungsi Init.

Fitur konstruktor:

  1. Nama fungsinya sama dengan nama kelasnya
  2. Tidak ada nilai kembalian (Anda tidak perlu memberikan apa pun sebagai nilai kembalian, dan jangan menulis void. Ini adalah aturan C++)
  3. Ketika objek dipakai, sistem akan secara otomatis memanggil konstruktor yang sesuai.
  4. Konstruktor bisa kelebihan beban
  5. Jika tidak ada konstruktor eksplisit yang ditentukan di kelas, kompiler C++ akan secara otomatis menghasilkan konstruktor default tanpa parameter. Setelah pengguna mendefinisikan konstruktor secara eksplisit, kompiler tidak akan lagi menghasilkannya.

  1. class Date
  2. {public:
  3. //1.无参构造函数
  4. Date()
  5. {
  6. _year = 1;
  7. _month = 1;
  8. _day = 1;
  9. }
  10. //2.带参构造函数
  11. Date(int year, int month, int day)
  12. {
  13. _year = year;
  14. _month = month;
  15. _day = day;
  16. }
  17. //3.全缺省构造函数
  18. Date(int year = 1, int month = 1, int day = 1)
  19. {
  20. _year = year;
  21. _month = month;
  22. _day = day;
  23. }
  24. private:
  25. int _year;
  26. int _month;
  27. int _day;
  28. };

Konstruktor tanpa argumen, konstruktor default, dan konstruktor yang dihasilkan oleh kompiler secara default ketika kita tidak menulis konstruktor semuanya disebut konstruktor default. Tapi hanya satu dari ketiganya yang bisa eksis, tidak pada waktu yang bersamaan. Meskipun konstruktor tanpa parameter dan konstruktor default penuh merupakan fungsi yang kelebihan beban, akan ada ambiguitas saat memanggilnya.Perhatikan bahwa tidak hanya konstruktor default yang dihasilkan oleh kompiler secara default, tetapi juga konstruktor, konstruktor tanpa parameter, dan konstruktor default penuh juga merupakan konstruktor default.

Kami tidak menulisnya. Konstruk yang dihasilkan oleh kompiler secara default tidak memiliki persyaratan untuk inisialisasi variabel anggota tipe bawaan. Artinya, apakah diinisialisasi atau tidak tidak pasti, itu tergantung pada kompiler.

  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. typedef int STDataType;
  5. class Stack
  6. {
  7. public:
  8. Stack(int n = 4)
  9. {
  10. _a = (STDataType*)malloc(sizeof(STDataType) * n);
  11. if (nullptr == _a)
  12. {
  13. perror("malloc申请失败");
  14. }
  15. _capacity = n;
  16. _top = 0;
  17. }
  18. private:
  19. STDataType* _a;
  20. size_t _capacity;
  21. size_t _top;
  22. };
  23. //两个Stack实现队列
  24. class MyQueue
  25. {
  26. private:
  27. int size;
  28. Stack pushst;
  29. Stack popst;
  30. };
  31. int main()
  32. {
  33. MyQueue my;
  34. return 0;
  35. }

C++ membagi tipe menjadi tipe khusus dan tipe bawaan (tipe dasar). Tipe bawaan adalah tipe data asli yang disediakan oleh bahasa, seperti int/char/double/pointer, dll. Tipe khusus adalah tipe yang kita definisikan sendiri menggunakan kata kunci seperti class/struct.Konstruktor di sini secara otomatis diinisialisasi, dan VS juga menginisialisasi ukuran tipe bawaan. Kompiler yang berbeda memiliki nilai inisialisasi yang berbeda, dan C++ tidak menentukannya.

Untuk variabel anggota tipe khusus, diperlukan untuk memanggil konstruktor default variabel anggota ini untuk menginisialisasinya.Jika variabel anggota ini tidak memiliki konstruktor default, kesalahan akan dilaporkan. Jika kita ingin menginisialisasi variabel anggota ini, kita perlu menggunakan daftar inisialisasi untuk menyelesaikannya.

Ringkasan: Dalam kebanyakan kasus, kita perlu mengimplementasikan konstruktornya sendiri. Dalam beberapa kasus, ini mirip dengan MyQueue dan ketika Stack memiliki konstruktor default, MyQueue dapat dibuat dan digunakan secara otomatis.

4.2 Destruktor

  1. ~Stack()
  2. {
  3. free(_a);
  4. _a = nullptr;
  5. _top = _capacity = 0;
  6. }

Karakteristik destruktor:

1. Nama destruktor diawali dengan karakter~

2. Tidak ada parameter dan tidak ada nilai kembalian (konsisten dengan konstruktor)

3. Sebuah kelas hanya dapat memiliki satu destruktor.Jika definisi tidak ditampilkan, sistem akan secara otomatis menghasilkan destruktor default.

4. Ketika siklus deklarasi objek berakhir, sistem akan secara otomatis memanggil destruktor.

5. Mirip dengan konstruktor, kami tidak menulis destruktor yang dihasilkan secara otomatis oleh kompiler dan tidak memproses anggota tipe bawaan. Anggota tipe khusus akan memanggil destruktor lain.

6. Perlu juga dicatat bahwa ketika kita menampilkan destruktor, destruktor dari anggota tipe khusus juga akan dipanggil, yang berarti bahwa destruktor dari anggota tipe khusus akan dipanggil secara otomatis apa pun situasinya.

  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. typedef int STDataType;
  5. class Stack
  6. {
  7. public:
  8. Stack(int n = 4)
  9. {
  10. _a = (STDataType*)malloc(sizeof(STDataType) * n);
  11. if (nullptr == _a)
  12. {
  13. perror("malloc申请失败");
  14. }
  15. _capacity = n;
  16. _top = 0;
  17. }
  18. ~Stack()
  19. {
  20. free(_a);
  21. _a = nullptr;
  22. _top=_capacity=0;
  23. }
  24. private:
  25. STDataType* _a;
  26. size_t _capacity;
  27. size_t _top;
  28. };
  29. //两个Stack实现队列
  30. class MyQueue
  31. {public:
  32. //编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化
  33. //编译器默认生成MyQueue的析构函数调用了Stack的析构,释放了Stack内部的资源
  34. //显示写析构也会调用Stack的析构
  35. ~MyQueue()
  36. {
  37. cout << "~MyQueue" << endl;
  38. }
  39. private:
  40. Stack pushst;
  41. Stack popst;
  42. };
  43. int main()
  44. {
  45. MyQueue my;
  46. return 0;
  47. }

Destruktor di MyQueue tidak melakukan apa pun, tetapi C++ menetapkan bahwa destruktor lain akan dipanggil untuk melepaskan memori.

Jika tidak ada sumber daya yang diminta, destruktor tidak perlu ditulis, dan destruktor default yang dihasilkan oleh kompiler dapat digunakan secara langsung, seperti Tanggal. Jika destruktor default yang dihasilkan dapat digunakan, tidak perlu menulis destruktor secara eksplisit seperti MyQueue, tetapi ada aplikasi sumber daya. Saat melakukan penghancuran, pastikan untuk menulis destruktor secara langsung, jika tidak maka akan menyebabkan kebocoran sumber daya seperti Stack

4.5 Kelebihan beban operator

  • Ketika operator digunakan pada objek yang diketik, bahasa C++ memungkinkan kita menentukan arti baru dalam bentuk kelebihan operator. C++ menetapkan bahwa ketika objek tipe kelas menggunakan operator, objek tersebut harus diubah menjadi panggilan ke operator yang berlebihan. Jika tidak, kompiler akan melaporkan kesalahan.
  • Operator kelebihan beban adalah suatu fungsi dengan nama tertentu. Namanya terdiri dari operator dan operator yang akan ditentukan kemudian.Seperti fungsi lainnya, fungsi ini juga memiliki tipe kembalian dan daftar parameter, serta isi fungsi
  1. bool operator<(Date d1, Date d2)
  2. {
  3. }
  4. bool operator==(Date d1,Date d2)
  5. {
  6. return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
  7. }
  • Fungsi operator yang kelebihan beban memerlukan parameter sebanyak parameter yang digunakan oleh operator.Kenyamanan transportasi unary memiliki satu parameter, dan operator biner memiliki dua parameter. Operan kiri dari operator biner diteruskan ke parameter pertama, dan operan kanan diteruskan ke parameter kedua.
  1. //text.cpp
  2. #include<iostream>
  3. using namespace std;
  4. class Date
  5. {
  6. public:
  7. Date(int year, int month, int day)
  8. {
  9. _year= year;
  10. _month = month;
  11. _day = day;
  12. }
  13. int _year;
  14. int _month;
  15. int _day;
  16. };
  17. bool operator<(Date d1, Date d2)
  18. {
  19. }
  20. bool operator==(Date d1,Date d2)
  21. {
  22. return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
  23. }
  24. int main()
  25. {
  26. Date d1(2024, 7, 10);
  27. Date d2(2024,7,9);
  28. //两种用法都可以
  29. d1 == d2;
  30. operator==(d1 , d2);
  31. return 0;
  32. }
  • Jika fungsi operator yang kelebihan beban adalah fungsi anggota, operan pertamanya diteruskan ke penunjuk implisit this secara default, ketika operator kelebihan beban sebagai fungsi anggota, ia memiliki satu parameter lebih sedikit daripada operan.
  • Setelah operator kelebihan beban, prioritas dan asosiatifnya tetap konsisten dengan jenis operasi bawaan.
  • Anda tidak dapat membuat operator seksual dengan menggabungkan kecocokan yang tidak ada dalam sintaksis: mis.