Teknologian jakaminen

C-perusteet (2)

2024-07-12

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

Sisällysluettelo

1. Luokat ja objektit

1.1 Luokan määritelmä

1.2 Käyttöoikeudet

1.3 Luokan verkkotunnus

2. Instantiaatio

2.1 Instantiation käsite

2.2 Objektin koko

3.tämä osoitin

4. Luokkien oletusjäsenfunktiot

4.1 Rakentaja

4.2 Tuhoaja

4.5 Kuljettajan ylikuormitus


1. Luokat ja objektit

1.1 Luokan määritelmä

Luokan määritelmän muoto

luokka on avainsana, joka määrittelee luokan, Pino on luokan nimi ja {} on luokan runko. Huomaa, että määritelmän lopussa olevaa puolipistettä ei jätetä pois. Luokan rungon sisältöä kutsutaan luokan jäseniksi: luokan muuttujia kutsutaan attribuuteiksi tai luokan jäsenmuuttujia luokan menetelmiksi tai jäsenfunktioiksi.

  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. }

  • Jäsenmuuttujien erottamiseksi on yleensä tavallista lisätä jäsenmuuttujaan erityinen tunniste, kuten alkava _ tai m_ ennen tai jälkeen jäsenmuuttujan.Tälle C++-syntaksille ei ole säännöksiä, se on vain henkilökohtainen tai yrityksen mieltymys.
  1. //为区分成员变量,一般前面加_
  2. //成员变量
  3. int* _a;
  4. int _top;
  5. int _capacity;
  • Struct C++:ssa voi myös määritellä luokkia C++:ssa. Samalla struct on päivitetty luokkaan silti suosittelemme käyttämään luokkaa luokkien määrittämiseen.

  • Luokassa määritellyt jäsenet ovat oletuksena rivissä

1.2 Käyttöoikeudet

C++ on tapa toteuttaa kapselointi, jossa luokkien avulla yhdistetään objektin ominaisuuksia ja menetelmiä objektin tekemiseksi täydellisemmäksi ja valikoivasti tarjotaan sen käyttöliittymä ulkoisille käyttäjille käyttöoikeuksien kautta.

  • Julkisesti (julkinen) muokattuihin jäseniin pääsee suoraan luokan ulkopuolelta, suojatulla (suojattu) ja yksityisellä (yksityinen) muokattuihin jäseniin ei pääse suoraan luokan ulkopuolelta, suojattu ja yksityinen ovat samat.
  • Käyttöoikeuden laajuus alkaa kohdasta, jossa käyttöoikeus näkyy, kunnes seuraava käyttöoikeustunnus ilmestyy.
  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. }

Lisämerkinnät:

  1. Kun pääsytunnistimet eivät muuta luokan määritelmän jäseniä, ne ovat oletuksena yksityisiä ja struct oletusarvoisesti public.
  2. Yleensä jäsenmuuttujat rajoitetaan yksityisiin/suojattuihin, ja jäsenfunktiot, joita muiden on käytettävä, sijoitetaan julkisiksi.

1.3 Luokan verkkotunnus

Luokka määrittelee uuden laajuuden. Kaikki luokan jäsenet ovat luokan ulkopuolella.

Luokkatoimialue vaikuttaa kääntämisen hakusääntöihin. Jos seuraavan ohjelman Init ei määritä luokan pinoa, kääntäjä käsittelee Initiä globaalina funktiona. Jos se ei löydä kääntämisen aikana jäseniä, kuten _top, se siirtyy luokan verkkotunnus löytää ne.

  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. }

Ilmoitus:

  1. Luokan funktiomääritykset ja -määritykset erotetaan toisistaan. Luokan luomisen jälkeen muodostetaan uusi luokka-alue.

2. Instantiaatio

2.1 Instantiation käsite

  • Tyypin luomista fyysiseen muistiin kutsutaan luokan ilmentymiseksi.
  • Luokka on objektin abstrakti kuvaus. Se rajoittaa luokan jäsenmuuttujia, eikä tilaa varata.

  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. }
  • Luokka voi instantoida useita objekteja, ja instantoidut objektit vievät todellista fyysistä tilaa ja tallentavat jäsenmuuttujia. Esimerkiksi: esineiden luominen luokasta on kuin arkkitehtonisten suunnittelupiirustusten käyttäminen talon rakentamiseen. Luokat ovat kuin suunnittelupiirustukset rakennus, ja se ei voi Asua ihmisissä, vain kun talo on rakennettu suunnittelupiirustusten mukaan, ihmiset voivat asua talossa.Sama luokka on kuin suunnittelupiirros. Se kertoo kääntäjälle, kuinka paljon muistia aiotaan avata, mutta se ei avaa muistia.
    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 Objektin koko

  • Analysoi mitä jäseniä luokkaobjektilla on? Jokaisella luokan instantoimalla objektilla on itsenäinen tietoavaruus, joten objektin tulee sisältää jäsenmuuttujia. Onko siis jäsenfunktioita mukana? Ensinnäkin, kun funktio on käännetty, se on käskyosio, jota ei voi tallentaa objektiin. Nämä käskyt tallennetaan erilliselle alueelle (koodisegmentti), joka voi olla vain osoitin jäsentoiminto. Pitääkö objektiin tallentaa osoittimia d1 ja d2 Sekä di:llä että d2:lla on itsenäiset jäsenmuuttujat _vuosi/_kuukausi/_päivä, mutta jäsenfunktiot d1 ja d2. /Print-osoitin? on sama, ja se menee hukkaan, jos se varastoidaan esineeseen. Jos käytät päivämäärää 100 objektin ilmentämiseen, jäsenfunktioosoitin tallennetaan toistuvasti 100 kertaa, mikä on liian turhaa. Itse asiassa funktion osoitinta ei tarvitse tallentaa. Kutsuva funktio käännetään kokoonpanokäskyksi [kutsun osoite]. Itse asiassa kääntäjän on löydettävä funktion osoite Sitä ei löydy ajon aikana. Tila löytyy ajon aikana, joten funktion osoite on tallennettava.

Muistin kohdistussäännöt

  • Ensimmäinen jäsen on osoitesiirrossa 0 rakenteesta
  • Muut jäsenmuuttujat on kohdistettava osoitteisiin, jotka ovat tasausnumeron kerrannaisia.
  • Tasausnumero = Kääntäjän oletuskohdistusnumero ja jäsenen koko pienempi
  • VS x64 -alustan oletuskohdistusnumero on 4 ja x86:n oletuskohdistusnumero on 8
  • Rakenteen kokonaiskoko on: suurimman kohdistusluvun kokonaislukukerrannainen (suurin kaikista tyyppimuuttujista ja pienin oletuskohdistusnumero)
  • Jos rakenteet ovat sisäkkäisiä, sisäkkäinen rakenne kohdistetaan sen oman enimmäiskohdistusluvun kokonaislukukerrannaiseen, ja rakenteen kokonaiskoko on kaikkien maksimikohdistuslukujen kokonaislukukerrannainen (mukaan lukien sisäkkäisten rakenteiden kohdistusmäärä).
  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.tämä osoitin

Kun kääntäjä on käännetty, luokan jäsenfunktiot lisäävät osoittimen nykyiseen luokkaan oletusarvoisesti muodollisen parametrin ensimmäiseen kohtaan, jota kutsutaan nimellä tämä osoitin.

Esimerkiksi Date-luokan Init-prototyyppi on void Init (Päivämäärä * const this, int vuosi, int kuukausi, int päivä) Kun päästään jäsenmuuttujiin luokan jäsenfunktioissa, essenssiin päästään tämän osoittimen kautta. kuten _year Init-funktiossa, tämä-&gt;_vuosi=vuosi

prototyyppi:

  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();

todellinen prototyyppi

  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++ määrää, että tätä osoitinta ei saa kirjoittaa todellisten parametrien ja muodollisten parametrien paikkaan (kääntäjä käsittelee sen käännettäessä), mutta tätä osoitinta voidaan käyttää eksplisiittisesti funktion rungossa tämän osoittimen osoittama sisältö voi

tämä osoitin on tallennettu pinoon

4. Luokkien oletusjäsenfunktiot

Oletusjäsenfunktio on jäsenfunktio, jota käyttäjä ei ole erikseen määritellyt ja jonka kääntäjä luo automaattisesti. Sitä kutsutaan oletusjäsenfunktioksi.

4.1 Rakentaja

Konstruktori on erityinen jäsenfunktio On huomattava, että vaikka konstruktoria kutsutaan rakentajaksi, konstruktorin pääsisältö ei ole avata tilaa objektien luomiseksi (yleensä käyttämämme paikallinen objekti on tila, joka avataan, kun se avataan. pinokehys luodaan) ), mutta objekti alustetaan, kun objekti instantoidaan. Konstruktorin ydin on korvata aiemmin pino- ja päivämääräluokissa kirjoittamamme Init-funktio. Konstruktorin automaattinen kutsu korvaa täydellisesti Init-funktion.

Rakentajan ominaisuudet:

  1. Toiminnon nimi on sama kuin luokan nimi
  2. Ei paluuarvoa (sinun ei tarvitse antaa mitään palautusarvona, äläkä kirjoita void-arvoa. Tämä on C++:n sääntö)
  3. Kun objekti on instantoitu, järjestelmä kutsuu automaattisesti vastaavaa rakentajaa.
  4. Rakentajat voivat olla ylikuormitettuja
  5. Jos luokassa ei ole määritetty eksplisiittistä konstruktoria, C++-kääntäjä luo automaattisesti parametrittoman oletuskonstruktorin Kun käyttäjä on nimenomaisesti määrittänyt rakentajan, kääntäjä ei enää luo sitä.

  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. };

Parametritonta rakentajaa, täysin oletuskonstruktoria ja kääntäjän oletusarvoisesti luomaa konstruktoria, kun emme kirjoita konstruktoria, kutsutaan kaikkia oletuskonstruktoreiksi. Mutta vain yksi näistä kolmesta voi olla olemassa, ei samanaikaisesti. Vaikka parametriton konstruktori ja täysi oletuskonstruktori muodostavat funktion ylikuormituksen, niitä kutsuttaessa esiintyy epäselvyyttä.Huomaa, että oletuskonstruktorin lisäksi kääntäjä ei ole oletuksena luonut, vaan se on konstruktori, parametriton konstruktori, ja koko oletuskonstruktori on myös oletuskonstruktori.

Emme kirjoita sitä. Kääntäjän luomalla konstruktilla ei ole oletuksena vaatimuksia sisäänrakennettujen jäsenmuuttujien alustamiselle, eli on epävarmaa, onko se alustettu vai ei, se riippuu kääntäjästä.

  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++ jakaa tyypit mukautetuiksi tyypeiksi ja sisäänrakennetuiksi tyypeiksi (perustyypit). Sisäänrakennetut tyypit ovat kielen tarjoamia alkuperäisiä tietotyyppejä, kuten int/char/double/pointer jne. Mukautetut tyypit ovat tyyppejä, jotka määrittelemme itse käyttämällä avainsanoja, kuten class/struct.Konstruktori alustetaan tässä automaattisesti, ja VS alustaa myös sisäänrakennetun tyyppikoon. Eri kääntäjillä on erilaiset alustusarvot, eikä C++ määritä niitä.

Mukautetun tyypin jäsenmuuttujien osalta on kutsuttava tämän jäsenmuuttujan oletuskonstruktori sen alustamiseksi.Jos tällä jäsenmuuttujalla ei ole oletuskonstruktoria, raportoidaan virhe. Jos haluamme alustaa tämän jäsenmuuttujan, meidän on käytettävä alustusluetteloa sen ratkaisemiseksi.

Yhteenveto: Useimmissa tapauksissa meidän on toteutettava rakentaja itse. Muutamissa tapauksissa se on samanlainen kuin MyQueue ja kun Stackilla on oletuskonstruktori, MyQueue voidaan luoda ja käyttää automaattisesti.

4.2 Tuhoaja

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

Destruktorin ominaisuudet:

1. Destruktorin nimeä edeltää merkit~

2. Ei parametreja eikä palautusarvoa (yhdenmukainen rakentajan kanssa)

3. Luokassa voi olla vain yksi tuhoaja.Jos määritelmää ei näytetä, järjestelmä luo automaattisesti oletushävittäjän.

4. Kun objektin määritysjakso päättyy, järjestelmä kutsuu automaattisesti tuhoajan.

5. Samoin kuin rakentaja, emme kirjoita kääntäjän automaattisesti luomaa destruktoria emmekä käsittele sisäänrakennettuja mukautetun tyypin jäseniä, jotka kutsuvat muita tuhoajia.

6. On myös huomattava, että kun näytämme destructorin, kutsutaan myös mukautetun tyypin jäsenen tuhoajaa, mikä tarkoittaa, että mukautetun tyypin jäsenen tuhoaja kutsutaan automaattisesti tilanteesta riippumatta.

  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. }

MyQueuen tuhoaja ei tee mitään, mutta C++ edellyttää, että muita tuhoajia kutsutaan vapauttamaan muisti.

Jos resursseja ei pyydetä, destruktoria ei tarvitse kirjoittaa, ja kääntäjän luomaa oletusdestruktoria voidaan käyttää suoraan, kuten Date. Jos luotua oletusdestruktoria voidaan käyttää, tuhoajaa ei tarvitse kirjoittaa erikseen kuten MyQueue, mutta siellä on resurssisovellus

4.5 Kuljettajan ylikuormitus

  • Kun operaattoreita käytetään kirjoitetuissa objekteissa, C++-kielen avulla voimme määrittää uusia merkityksiä operaattorin ylikuormituksen muodossa. C++ edellyttää, että kun luokkatyyppinen objekti käyttää operaattoria, se on muutettava kutsuksi vastaavalle operaattorin ylikuormitukselle. Jos ei, kääntäjä ilmoittaa virheestä.
  • Operaattorin ylikuormitus on funktio, jolla on tietty nimi Sen nimi koostuu operaattorista ja myöhemmin määritettävästä operaattorista.Kuten muillakin funktioilla, sillä on myös palautustyyppi ja parametriluettelo sekä funktion runko
  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. }
  • Ylikuormitettu käyttötoiminto ottaa yhtä monta parametria kuin ne parametrit, joihin käyttäjä vaikuttaa.Unaarisella siirtomukavuudella on yksi parametri ja binäärioperaattorilla kaksi parametria. Binäärioperaattorin vasen operandi välitetään ensimmäiseen parametriin ja oikea operandi toiseen parametriin.
  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. }
  • Jos ylikuormitettu operaattorifunktio on jäsenfunktio, sen ensimmäinen operandi välitetään oletuksena implisiittiselle osoittimelle. Siksi, kun operaattori on ylikuormitettu jäsenfunktiona, sillä on yksi parametri vähemmän kuin operandi.
  • Kun operaattori on ylikuormitettu, sen ensisijaisuus ja assosiatiivisuus pysyvät yhdenmukaisina sisäänrakennettujen tyyppitoimintojen kanssa.
  • Et voi luoda seksuaalista operaattoria ketjuttamalla osumia, joita ei ole syntaksissa: esim. operator@.