2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Sisällysluettelo
Prosessisuuntautunut ja oliosuuntautunut
2. Luokkapääsyn tarkenteet ja kapselointi
Prosessisuuntautunut ohjelmointi on prosessikeskeinen ohjelmointiidea. Prosessisuuntautuneessa ohjelmoinnissa ohjelmaa pidetään kokoelmana toimintoja tai proseduureja, jotka suoritetaan tietyssä järjestyksessä tietyn tehtävän suorittamiseksi.
etu:
- Suorituskyky tehokas : Koska prosessisuuntautunut ohjelmointi suorittaa tehtävät suoraan prosessin mukaisesti eikä vaadi liiallista objektin luomista ja hallintaa, sen suoritustehokkuus on korkeampi joissakin skenaarioissa, joissa suorituskykyvaatimukset ovat korkeammat, kuten taustalla oleva järjestelmäohjelmointi, sulautettu ohjelmointi jne. Esimerkiksi käyttöjärjestelmän ytimessä prosessilähtöistä ohjelmointia voidaan käyttää paremmin optimoimaan suorituskykyä toimintojen, kuten prosessien ajoituksen ja muistinhallinnan, toteuttamiseksi.
- selkeä logiikka : Yksinkertaista ohjelmalogiikkaa varten se toteutetaan vaiheittain prosessin mukaisesti. Koodin looginen rakenne on selkeä ja helppo ymmärtää, helppo ymmärtää ja ylläpitää. Esimerkiksi yksinkertainen ohjelma, joka laskee kahden luvun summan, voi määrittää suoraan funktion laskentaa varten prosessisuuntautuneen ohjelmoinnin avulla.
puute:
- Huono huollettavuus : Kun ohjelman koko kasvaa ja toiminnoista tulee monimutkaisia, proseduuriohjelmointisuuntautunutta koodia voi olla vaikea ylläpitää ja laajentaa. Koska eri toimintojen välinen kytkentä on suuri, yhden toiminnon muuttaminen voi vaikuttaa muihin liittyviin toimintoihin.
- Matala koodin uudelleenkäytettävyys: Koodin uudelleenkäyttö saavutetaan yleensä funktiokutsujen avulla, mutta monimutkaisissa toiminnallisissa moduuleissa uudelleenkäyttö on vaikeampaa, eikä toimintoja voida hyvin kapseloida ja abstrakteja.
Olio-ohjelmointi on oliokeskeinen ohjelmointiidea. Objektit ovat entiteettejä, jotka sisältävät dataa (ominaisuuksia) ja menetelmiä (käyttäytymistä), jotka toimivat kyseisellä tiedolla. Kapseloimalla toisiinsa liittyvät tiedot ja menetelmät objektiin saavutetaan tietojen ja toimintojen integrointi.
etu:
- Korkea huollettavuus : Kapseloi toiminnot objekteihin piilottamalla objektien sisäisen toteutuksen ulkopuolelta ja vähentämällä moduulien välistä kytkentää. Kun toimintoa on muutettava, vain vastaavan objektin sisäistä toteutusta tarvitsee muokata vaikuttamatta muihin asiaankuulumattomiin osiin. Esimerkiksi graafisessa käyttöliittymäsovelluksessa, jos haluat muokata painikkeen toimintoa, sinun tarvitsee vain muokata painikeobjektin vastaavaa menetelmää vaikuttamatta muihin käyttöliittymäelementteihin.
- Vahva koodin uudelleenkäytettävyys : Koodin uudelleenkäyttö ja laajentaminen voidaan saavuttaa helposti periytymisen, polymorfismin ja muiden ominaisuuksien avulla.Luo esimerkiksi perusluokka
Shape
(muoto) ja johda sittenCircle
(pyöristää),Rectangle
(Rectangle) ja muut alaluokat, alaluokat voivat käyttää uudelleen perusluokan attribuutteja ja menetelmiä ja tehdä erityisiä laajennuksia.- Hyvä joustavuus: Olio-ohjelmointi tukee polymorfismia, jonka avulla ohjelma voi dynaamisesti valita ja suorittaa vastaavat menetelmät objektin todellisen tyypin mukaan ajon aikana, mikä lisää ohjelman joustavuutta ja skaalautuvuutta.
puute:
- Suorituskyky yläpuolella: Koska objektin luominen, menetelmän kutsuminen ja muut toiminnot vaativat tietyn määrän lisäkustannuksia, joissakin skenaarioissa, joissa suorituskykyvaatimukset ovat erittäin korkeat, se voi vaikuttaa ohjelman suoritustehokkuuteen.
- Korkeat oppimiskustannukset: Olio-ohjelmoinnin käsitteet ja ominaisuudet ovat suhteellisen monimutkaisia, mikä vaikeuttaa aloittelijoiden oppimista ja ymmärtämistä.
• class on avainsana, joka määrittelee luokan, Data on luokan nimi ja {} on luokan runko. Huomaa, että luokan määritelmän lopussa olevaa puolipistettä ei voi jättää pois. Luokan rungon sisältöä kutsutaan luokan jäseniksi: luokan muuttujia kutsutaan attribuuteiksi tai luokan jäsenmuuttujia luokan menetelmiksi tai jäsenfunktioiksi.
• Jäsenmuuttujien erottamiseksi on yleensä tapana lisätä jäsenmuuttujaan erityinen tunniste, kuten _ tai m alkava merkki ennen tai jälkeen jäsenmuuttujan. Huomaa, että tämä ei ole pakollista C++:ssa, se on vain joitakin käytäntöjä .
• C++:ssa struct voi määritellä luokkia C++:n kanssa. Samalla struct on päivitetty luokkaan. Yleensä se on funktioita on suositeltavaa käyttää luokkaa luokkien määrittämiseen.
• Luokassa määritellyt jäsenfunktiot ovat oletuksena rivissä.
class Date { public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } private: // 为了区分成员变量,⼀般习惯上成员变量 // 会加⼀个特殊标识,如_ 或者 m开头 int _year; // year_ m_year int _month; int _day; }; int main() { Date d; d.Init(2024, 3, 31); return 0; }
• Luokka määrittelee uuden laajuuden Kaikki luokan jäsenet ovat luokan piirissä.
• Luokka-alue vaikuttaa kääntämisen hakusääntöihin. Jos Init ei määritä seuraavan ohjelman luokka-aluetta, kääntäjä käsittelee Initiä globaalina funktiona löydetty, ilmoitetaan virheestä. Luokkaalueen pinon määrittäminen tarkoittaa, että tiedetään, että Init on jäsenfunktio. Jos jäseniä, kuten taulukkoa, ei löydy nykyisestä toimialueesta, niitä etsitään luokkatoimialueelta.
- #include<iostream>
- using namespace std;
- class Stack
- {
- public:
- // 成员函数
- void Init(int n = 4);
- private:
- // 成员变量
- int* array;
- size_t capacity;
- size_t top;
- };
- // 声明和定义分离,需要指定类域
- void Stack::Init(int n)
- {
- array = (int*)malloc(sizeof(int) * n);
- if (nullptr == array)
- {
- perror("malloc申请空间失败");
- return;
- }
- capacity = n;
- top = 0;
- }
- int main()
- {
- Stack st;
- st.Init();
- return 0;
- }
• C++ on tapa toteuttaa kapselointi, jossa luokkien avulla yhdistetään objektin ominaisuuksia ja menetelmiä, jotta objektista tulee täydellisempi, ja tarjotaan valikoivasti sen liitännät ulkoisille käyttäjille käyttöoikeuksien kautta.
• Julkisesti muokattuihin jäseniin pääsee suoraan luokan ulkopuolelta. Suojatut ja yksityiset ovat samat, ja niiden erot näkyvät myöhemmin.
• Käyttöoikeuksien laajuus alkaa kohdasta, jossa käyttöoikeustunniste tulee näkyviin, kunnes seuraava käyttöoikeustunniste tulee näkyviin.
• Kun käyttöoikeustunniste ei muokkaa luokan määritelmän jäsentä, se on oletuksena yksityinen.
• struct oletuksena on julkinen
• Yleensä jäsenmuuttujat rajoitetaan yksityisiin/suojattuihin ja jäsenfunktiot, joita muiden on käytettävä, julkistetaan.
Oliosuuntautuneisuuden kolme pääominaisuutta: kapselointi, periytyminen ja polymorfismi.
Luokka- ja objektivaiheessa tutkimme pääasiassa luokkien kapselointiominaisuuksia. Mitä siis kapselointi on?
Kapselointi: Yhdistä orgaanisesti tiedot ja käyttötietojen menetelmät, piilota objektin ominaisuudet ja toteutustiedot ja paljasta rajapinta vain vuorovaikutukseen kohteen kanssa.
Kapselointi on pohjimmiltaan eräänlainen hallinta, joka helpottaa käyttäjien luokkien käyttöä. Esimerkki: Monimutkaisessa laitteessa, kuten tietokoneessa, käyttäjälle tarjotaan vain virtanäppäimet, näppäimistön tulo, näyttö, USB-liitäntä jne., joiden avulla käyttäjä voi olla vuorovaikutuksessa tietokoneen kanssa ja suorittaa päivittäisiä tehtäviä. Mutta itse asiassa tietokoneen todellinen työ on suoritin, näytönohjain, muisti ja muut laitteistokomponentit.
Tietokoneen käyttäjien ei tarvitse huolehtia sisäisistä ydinkomponenteista, kuten siitä, miten emolevyn piirit on järjestetty, miten suoritin on suunniteltu jne. Käyttäjien tarvitsee vain tietää, miten tietokone kytketään päälle ja miten olla vuorovaikutuksessa tietokoneen kanssa näppäimistön ja hiiren avulla. Siksi, kun tietokonevalmistajat lähtevät tehtaalta, ne laittavat ulkopuolelle kuoren piilottaakseen sisäiset toteutustiedot ja tarjoavat vain virtakytkimiä, hiiri- ja näppäimistöliittimiä ulkopuolelle, jotta käyttäjät voivat olla vuorovaikutuksessa tietokoneen kanssa.
Kapseloinnin toteuttamiseksi C++-kielellä käyttödatan dataa ja menetelmiä voidaan yhdistää orgaanisesti luokkien kautta ja käyttöoikeuksilla voidaan piilottaa objektien sisäiset toteutustiedot ja hallita, mitä menetelmiä voidaan käyttää suoraan luokan ulkopuolella.
• Objektin luomista fyysiseen muistiin käyttämällä luokkatyyppiä kutsutaan luokan ilmentymiseksi.
• Luokka on objektin abstrakti kuvaus, joka rajoittaa luokan jäsenmuuttujia luokkaa.
• Luokka voi instantoida useita objekteja. Instantoidut objektit vievät todellista fyysistä tilaa ja tallentavat luokan jäsenmuuttujia. Esimerkiksi: esineiden luominen luokasta on kuin arkkitehtonisten suunnittelupiirustusten käyttäminen talon rakentamiseen. Luokka on kuin suunnittelupiirros ei ole fyysinen esine, vaikka rakennus olisi olemassa, se ei voi asua ihmisissä. Sama luokka on kuin suunnittelupiirustus, eikä se voi tallentaa tietoja.
Analysoi, mitkä jäsenet ovat luokkaobjektissa? 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 on tallennettu erilliselle alueelle (koodisegmentille), joten jos ne on tallennettava objektiin, ne voivat olla vain osoittimia jäsentoimintoihin. Analysoidaan vielä, onko tarpeen tallentaa osoittimia objektiin d1 ja d2 Sekä d1:llä että d2:lla on omat itsenäiset jäsenmuuttujat _vuosi/_kuukausi/_päivä omien tietojensa tallentamiseen, mutta jäsenfunktio Init/Print? d1:n ja d2:n osoittimet ovat samat, joten niiden tallentaminen objekteihin on turhaa. Jos käytät päivämäärää 100 objektin ilmentämiseen, jäsenfunktioosoitin tallennetaan 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 , ei ajon aikana. Vain dynaaminen polymorfismi löytyy ajon aikana, ja funktioosoitteet on tallennettava.
Yllä analysoimme, että vain jäsenmuuttujat tallennetaan objekteihin. C++ edellyttää, että luokkien luomien objektien on myös noudatettava muistin kohdistussääntöjä.
Muistin kohdistussäännöt
Muistin kohdistussäännöt ovat täsmälleen samat kuin C-kielen säännötViiteartikkeli:C-kieli muistin kohdistuksen laskemiseen
Ensimmäinen jäsen on osoitteen siirrossa 0 rakenteesta.
• Muut jäsenmuuttujat tulee yhdistää osoitteisiin, jotka ovat tietyn luvun (tasausnumeron) kokonaislukukertoja.
• Huomautus: Logaritmi = pienempi kääntäjän oletuskohdistusnumero ja jäsenen koko.
• VS:n oletuslogaritmi on 8
• Rakenteen kokonaiskoko on: suurimman kohdistusluvun kokonaislukukerrannainen (suurin kaikista muuttujatyypeistä ja pienin oletuskohdistusparametri).
• Jos rakenne on sisäkkäinen ja sisäkkäinen rakenne on kohdistettu sen oman maksimilogaritmin kokonaislukukerrannaiseen, rakenteen kokonaiskoko on kaikkien (mukaan lukien sisäkkäisen rakenteen tasaus) lukujen suurin tasausluku).
Jos jäsenmuuttujaa ei ole, on annettava 1 tavu, koska jos tavua ei anneta, miten voidaan osoittaa, että olio on ollut olemassa? Joten 1 tavu annetaan tässä puhtaasti objektin olemassaolon paikkamerkkitunnistukseen.
Date-luokassa on kaksi jäsenfunktiota, Init ja Print. Funktion rungossa ei ole eroa eri objektien välillä. Joten kun d1 kutsuu Init- ja Print-funktioita, mistä funktio tietää, pitäisikö sen käyttää d1-objektia. d2-objekti?Sitten täällä näemme, että C++ antaa implisiittisen tämän osoittimen ongelman ratkaisemiseksi.
• Kun kääntäjä on käännetty, luokan jäsenfunktiot lisäävät oletusarvoisesti muodollisen parametrin ensimmäiseen paikkaan nykyisen luokkatyypin osoittimen, jota kutsutaan nimellä tämä osoitin. Esimerkiksi Init of Date -luokan todellinen prototyyppi onvoid Init(Päivämäärä* const this, int vuosi, int kuukausi, int päivä) • Kun päästään jäsenmuuttujiin luokan jäsenfunktioissa, niihin päästään olennaisesti tämän osoittimen kautta. Esimerkiksi kun määritetään arvo _yearille Init-funktiossa, tämä ->_vuosi = vuosi;
• C++ edellyttää, että tätä osoitinta ei voi kirjoittaa eksplisiittisesti todellisten parametrien ja muodollisten parametrien paikkaan (kääntäjä käsittelee sen kääntämisen aikana), mutta tätä osoitinta voidaan käyttää eksplisiittisesti funktion rungossa.
- #include<iostream>
- using namespace std;
- 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(2024, 7, 1); // d1.Init(&d1, 2024, 7, 1);
- d1.Print(); // d1.Print(&d1);
- d2.Init(2024, 7, 10); // d2.Init(&d2, 2024, 7, 10);
- d2.Print(); // d2.Print(&d2);
- return 0;
- }