Lausunto käyttämällä nimiavaruutta std pidetään yleisesti huonona käytäntönä. Vaihtoehto tälle käskylle on määrittää nimiavaruus, johon tunniste kuuluu, käyttämällä soveltamisala-operaattoria (::) joka kerta, kun ilmoitamme tyypin.
Vaikka lausunto säästää meidät kirjoittamiselta std:: aina kun haluamme käyttää std-nimiavaruudessa määritettyä luokkaa tai tyyppiä, se tuo koko std nimiavaruus ohjelman nykyiseen nimiavaruuteen. Otetaan muutama esimerkki ymmärtääksemme, miksi tämä ei ehkä ole niin hyvä asia
Oletetaan, että haluamme käyttää std-nimiavaruuden cout-komentoa. Joten kirjoitamme
Esimerkki 1:
CPP
raja css:llä
#include> using> namespace> std;> > cout <<>' Something to Display'>;> |
>
>
Nyt myöhemmässä kehitysvaiheessa haluamme käyttää toista cout-versiota, joka on mukautettuna toteutettu jossain kirjastossa nimeltä foo (esim.
CPP
#include> #include> using> namespace> std;> > cout <<>' Something to display'>;> |
>
>
Huomaa nyt, että on epäselvyyttä, mihin kirjastoon se viittaa? Kääntäjä saattaa havaita tämän eikä käännä ohjelmaa. Pahimmassa tapauksessa ohjelma saattaa silti kääntää mutta kutsua väärän funktion, koska emme koskaan määrittäneet mihin nimiavaruuteen tunniste kuuluu.
Nimiavaruudet otettiin käyttöön C++:ssa tunnisteiden nimiristiriitojen ratkaisemiseksi. Tämä varmisti, että kahdella objektilla voi olla sama nimi ja silti niitä kohdellaan eri tavalla, jos ne kuuluivat eri nimiavaruuksiin. Huomaa, kuinka tässä esimerkissä on tapahtunut täsmälleen päinvastoin. Nimiristiriidan ratkaisemisen sijaan luomme itse asiassa nimiristiriidan.
Kun tuomme nimiavaruuden, vedämme periaatteessa kaikki tyyppimääritykset nykyiseen soveltamisalaan. Std-nimiavaruus on valtava. Siinä on satoja ennalta määritettyjä tunnisteita, joten on mahdollista, että kehittäjä jättää huomiotta sen tosiasian, että std-kirjastossa on toinen määritelmä heidän aiotulle objektilleen. Tietämättä tätä he voivat ryhtyä määrittelemään omaa toteutustaan ja odottaa sen käytettävän ohjelman myöhemmissä osissa. Siten nykyisessä nimiavaruudessa olisi kaksi määritelmää samalle tyypille. Tämä ei ole sallittua C++:ssa, ja vaikka ohjelma kääntäisi, ei ole mitään keinoa tietää, mitä määritelmää käytetään missä.
Ratkaisu ongelmaan on määrittää eksplisiittisesti, mihin nimiavaruuteen tunnuksemme kuuluu käyttämällä alueoperaattoria (::). Näin ollen yksi mahdollinen ratkaisu yllä olevaan esimerkkiin voi olla
CPP
#include> #include> > // Use cout of std library> std::cout <<>'Something to display'>;> > // Use cout of foo library> foo::cout <>'Something to display'>;> |
>
>
Mutta pakko kirjoittaa std:: joka kerta kun määrittelemme tyypin, on tylsää. Se saa myös koodimme näyttämään karvaisemmalta monien tyyppimääritelmien ansiosta ja vaikeuttaa koodin lukemista. Harkitse esimerkiksi koodia nykyisen ajan saamiseksi ohjelmaan
Esimerkki 2:
CPP
#include> #include> > auto> start = std::chrono::high_performance_clock::now()> > // Do Something> > auto> stop> >= std::chrono::high_peformance_clock::now();> auto> duration> >= std::duration_cast(stop - start);> |
>
>
Monimutkaisia ja pitkiä tyyppimääritelmiä täynnä olevaa lähdekoodia ei ole kovin helppo lukea. Tätä kehittäjät pyrkivät välttämään, koska koodin ylläpito on heille ensisijaisen tärkeää.
On olemassa muutamia tapoja ratkaista tämä ongelma, eli määrittää tarkka nimiavaruus roskaamatta koodia std-avainsanoilla.
Harkitse typedefien käyttöä
typedefs säästää meitä kirjoittamasta pitkiä tyyppimääritelmiä. Esimerkissämme 1 voisimme ratkaista ongelman käyttämällä kahta typedefiä, joista toinen on std-kirjasto ja toinen foo.
CPP
#include> #include> > typedef> std::cout cout_std;> typedef> foo::cout cout_foo;> > cout_std <<>'Something to write'>;> cout_foo <<>'Something to write'>;> |
>
>
Kokonaisten nimiavaruuksien tuomisen sijaan tuo katkaistu nimiavaruus
Esimerkissä 2 olisimme voineet tuoda vain chronon nimiavaruuden std:n alle.
CPP
#include> #include> > // Import only the chrono namespace under std> using> std::chrono;> > auto> start = high_performance_clock::now();> > // Do Something> auto> stop = high_performance_clock::now();> auto> duration duration_cast(stop - start);> |
>
>
Voimme käyttää käskyä myös yhden tunnisteen tuomiseen. Voisimme käyttää tuodaksesi vain std::cout
using std::cout;>
Jos tuot edelleen kokonaisia nimiavaruuksia, yritä tehdä se funktioissa tai rajoitetussa laajuudessa, ei globaalissa laajuudessa.
Käytä using namespace std -käskyä funktiomäärittelyissä tai luokka-, struct-määritelmissä. Tällöin nimiavaruuden määritelmät tuodaan paikalliseen laajuuteen, ja tiedämme ainakin mistä mahdolliset virheet voivat johtua, jos niitä ilmenee.
CPP
milloin windows 7 ilmestyi
#include> > // Avoid this> using> namespace> std;> > void> foo()> {> >// Inside function> >// Use the import statement inside limited scope> >using> namespace> std;> > >// Proceed with function> }> |
>
>
Johtopäätös.
Olemme keskustelleet vaihtoehtoisista menetelmistä tunnisteen saamiseksi nimiavaruudesta. Vältä kaikissa tapauksissa tuomasta kokonaisia nimiavaruuksia lähdekoodiin.
Vaikka hyvien koodauskäytäntöjen oppiminen ja kehittyminen voi viedä jonkin aikaa, ne yleensä kannattavat pitkällä aikavälillä. Puhtaan, yksiselitteisen ja vankan, virheettömän koodin kirjoittamisen tulisi olla jokaisen ohjelmointikehittäjän tarkoitus.