C++ | ||
---|---|---|
Utvikler(e) | ||
Bjarne Stroustrup , Bell Laboratories https://isocpp.org/ og http://www.open-std.org/jtc1/sc22/wg21/ | ||
Generell informasjon | ||
Vanlige utvidelser | .h .hh .hpp .hxx .h++ .cc .cpp .cxx .c++ | |
Paradigme | Multiparadigme : Strukturert programmering , imperativ , generisk programmering | |
Dukket opp i | 1983 | |
Designet av | Bjarne Stroustrup | |
Siste stabile versjon | ISO/IEC 14882:2017 ( C++17 ) [ 1 ] ( 15. desember 2017 (4 år, 10 måneder og 1 dag)) | |
Siste versjon i tester | C++20 (2020) | |
type system | sterk, statisk, nominativ | |
implementeringer | C++ Builder , clang , Comeau C/C++ , GCC , Intel C++ Compiler , Microsoft Visual C++ , Sun Studio, Code::Blocks , Zinjai | |
dialekter | ISO/IEC C++ 1998, ISO/IEC C++ 2003, ISO/IEC C++ 2011 | |
påvirket av | C , Simula , Ada 83 , ALGOL 68 , CLU , ML [ 2 ] | |
har påvirket | Perl , LPC, Lua , Pike, Ada 95 , Java , PHP , D , C99 , C# , Falcon | |
Operativsystem | Multiplattform | |
C++ er et programmeringsspråk designet i 1979 av Bjarne Stroustrup . Intensjonen med opprettelsen var å utvide programmeringsspråket C og legge til mekanismer som tillater manipulering av objekter . I den forstand, fra objektorienterte språks synspunkt , er C++ et hybridspråk.
Generiske programmeringsfasiliteter ble senere lagt til , og la til de strukturerte programmerings- og objektorienterte programmeringsparadigmene . Dette er grunnen til at C++ ofte sies å være et programmeringsspråk med flere paradigmer .
Det er nå en standard, kalt ISO C++, som de fleste moderne kompilatorleverandører har fulgt. Det finnes også noen tolker, som ROOT.
Navnet "C++" ble foreslått av Rick Mascitti i 1983, da språket først ble brukt utenfor et vitenskapelig laboratorium. Tidligere var navnet "C med klasser" brukt. I C++ betyr uttrykket "C++" "økende C" og refererer til at C++ er en utvidelse av C.
Her er et eksempel på Hello World- program skrevet i C++:
/* Denne overskriften lar deg bruke objektene som kapsler inn stdout- og stdin-beskrivelsene: cout(<<) og cin(>>)*/ #include <iostream> bruker navneområde std ; intmain ( ) { cout << "Hei verden" << endl ; returner 0 ; }Bruk av direktivet #includeforteller kompilatoren å finne og tolke alle elementene som er definert i filen som følger med direktivet (i dette tilfellet iostream). For å unngå å overskrive elementene som allerede er definert ved å gi dem samme navn, namespaceble det opprettet navneområder eller entall på engelsk. I dette tilfellet er det et navneområde kalt std, som er der definisjonene av alle funksjonene og klassene som utgjør C++-standardbiblioteket er inkludert. Ved å inkludere setningen using namespace stdforteller vi kompilatoren at vi vil bruke navneområdet stdslik at vi ikke trenger å inkludere det når vi bruker elementer i dette navnerommet, for eksempel coutog objekter cin, som representerer standard utdatastrøm (vanligvis skjermen eller en tekst vindu) og standard inndatastrøm (vanligvis tastaturet).
Definisjonen av funksjoner er den samme som i C, bortsett fra karakteristikken at hvis mainden ikke skal samle argumenter, trenger vi ikke å sette dem, i motsetning til i C, hvor de måtte settes eksplisitt, selv om de ikke var det. skal brukes. Det gjenstår bare å kommentere at symbolet <<er kjent som en innsettingsoperator, og grovt sett sender coutdet det vi ønsker å vise på skjermen som skal males, i dette tilfellet strengen "Hola mundo". Den samme operatøren <<kan brukes flere ganger i den samme setningen, så takket være denne funksjonen kan vi sette sammen objektet endlpå slutten, resultatet av dette vil være å skrive ut en linjeretur.
C++ har følgende grunnleggende typer :
Modifikatoren unsignedkan brukes på heltall for å få usignerte tall (heltall er fortegnet som standard), og dermed oppnå et større utvalg av naturlige tall.
Avhengig av maskinen og kompilatoren som brukes, kan de primitive typene oppta en viss størrelse i minnet. Følgende liste illustrerer antall biter som er okkupert av de forskjellige primitive typene på x86 -arkitekturen .
Fyr | antall biter |
char | 8 |
short | 16 |
int | 32 |
float | 32 |
double | 64 |
Andre arkitekturer kan kreve forskjellige størrelser av primitive datatyper. C++ sier ingenting om antall biter i en byte, eller størrelsen på disse typene; snarere tilbyr den bare følgende "typegarantier":
For versjonen av standarden som ble publisert i 1998, ble det besluttet å legge til datatypen wchar_t, som tillater bruk av UNICODE -tegn , i motsetning til den tradisjonelle char, som ganske enkelt vurderer den utvidede ASCII-tegnkoden. I sin tur, for de fleste funksjoner og klasser, både i C og C++, er det definert en versjon for å jobbe med , der tegnet wwchar_t vanligvis settes foran navnet på funksjonen (noen ganger er tegnet et infiks) . For eksempel:
Det skal bemerkes at i C er det definert wchar_tsom:
typedef usignert kort wchar_t ;Mens i C++ er det i seg selv en datatype.
Det reserverte ordet voiddefinerer i C++ begrepet ikke-eksistens eller ikke-attribusjon av en type i en variabel eller erklæring. Det vil si at en funksjon erklært som voidikke vil returnere noen verdi. Dette nøkkelordet kan også brukes til å indikere at en funksjon ikke tar noen parametere, som i følgende erklæring:
int funksjon ( void );Selv om den nåværende trenden ikke er å plassere ordet "tomt".
Den brukes også til å bestemme at en funksjon ikke returnerer en verdi, som i:
void funksjon ( int parameter );Merk at voiddet ikke er en type . En funksjon som den som er deklarert ovenfor kan ikke returnere en verdi via retur : nøkkelordet går av seg selv. En typeerklæring er ikke mulig:
ugyldig t ; //Det er feilSlik voidsett oppfører den seg litt annerledes enn den gjør i C, spesielt når det gjelder betydningen i funksjonserklæringer og prototyper.
Den spesielle formen void * indikerer imidlertid at datatypen er en peker. For eksempel:
void * minne ;Det indikerer at minnet er en peker til et sted hvor informasjon av noe slag er lagret . Programmereren er ansvarlig for å definere disse "noen" , og fjerne all tvetydighet. En fordel med " void * " -erklæringen er at den kan representere flere datatyper samtidig, avhengig av den valgte cast - operasjonen . Minnet som vi har pekt på et sted i eksemplet ovenfor kan godt lagre et heltall, en flottør, en streng eller et program, eller kombinasjoner av disse. Det er programmererens ansvar å huske hva slags data som finnes og sørge for riktig tilgang.
I tillegg til verdiene som de nevnte typene kan ta, er det en verdi som kalles NULL, enten det gjelder tall for heltall, tegn for tegntypen, tekststreng for strengtypen, etc. NULL-verdien uttrykker vanligvis representasjonen av en makro, tildelt verdien "0".
Da har vi det:
void * peker = NULL ; int heltall = NULL ; bool boolean = NULL ; char- tegn = NULL ;Verdien av variablene ovenfor vil gi oss 0. I motsetning til "character"-variabelen, som vil gi oss ekvivalenten til NULL, '\0', for tegn.
For å unngå tvetydighet i overbelastede funksjoner, kan nøkkelordet nullptr brukes . Dette nøkkelordet representerer alltid en peker. For eksempel:
void f ( int a ); void f ( foo * a ); int main ( int argc , char ** argv ) { f ( NULL ); // Utfør f(int a) f ( nullptr ); // Utfør f(foo *a) return 0 ; }Hvert C++-program må ha hovedfunksjonen main()(med mindre et annet inngangspunkt er spesifisert på kompileringstidspunktet, som faktisk er funksjonen som har main())
intmain ( ) {}Hovedkildekodefunksjonen main må ha en av følgende prototyper:
int main()
int main(int argc, char** argv)
Selv om det ikke er standard, tillater noen implementeringer
int main(int argc, char** argv, char** env)
Den første er standardformen til et program som ikke tar noen parametere eller argumenter. Den andre formen har to parametere: argc , et tall som beskriver antall argumenter til programmet (inkludert navnet på selve programmet), og argv , en peker til en rekke pekere, av argc- elementer, der elementet argv[i ] representerer ith - argumentet gitt til programmet. I det tredje tilfellet legges muligheten for å få tilgang til utførelsesmiljøvariablene på samme måte som programargumentene aksesseres, men reflekteres på env -variabelen .
Returtypen for hoved er en heltallsverdi int . På slutten av funksjonen mainmå returverdien inkluderes (for eksempel return 0; , selv om standarden gir kun to mulige returverdier: EXIT_SUCCESS og EXIT_FAILURE, definert i cstdlib -filen ), eller exit via exit -funksjonen . Den kan alternativt stå tom, i så fall er kompilatoren ansvarlig for å legge til riktig utgang.
Objekter i C++ abstraheres av en klasse. I følge det objektorienterte programmeringsparadigmet består et objekt av:
Et eksempel på en klasse som vi kan ta er hundeklassen. Hver hund deler noen egenskaper (attributter). Dens antall ben, fargen på pelsen eller størrelsen er noen av dens attributter. Funksjonene som får den til å bjeffe, endre oppførselen... det er funksjonene til klassen.
Dette er et annet eksempel på en klasse:
klasse Punkt { //som standard er medlemmer 'private' så de kan bare endres fra selve klassen. privat : // privat medlemsvariabel int id ; beskyttet : // Beskyttede medlemsvariabler int x ; int og ; offentlig : // Constructor Point (); // Destructor ~ Point (); // Medlemsfunksjoner eller metoder int GetX (); int GetAND (); };De er spesielle metoder som kjøres automatisk når du oppretter et objekt i klassen. Hvilken type data de returnerer er ikke spesifisert i deres erklæring, og de har samme navn som klassen de tilhører. Som andre metoder kan det være flere overbelastede konstruktører, selv om ingen virtuelle konstruktører kan eksistere.
Som en spesiell funksjon ved implementering av en konstruktør, rett etter deklarasjonen av parameterne, er det det som kalles "initialiseringslisten". Målet er å kalle konstruktørene av attributtene som utgjør objektet som skal konstrueres.
Det skal bemerkes at det ikke er nødvendig å deklarere en konstruktør så vel som en destruktor, siden kompilatoren kan gjøre det, selv om det ikke er den beste måten å programmere på.
Hvis vi tar eksempelet med punktklassen, hvis vi vil at koordinatene til punktet skal være lik null hver gang et objekt av denne klassen opprettes, kan vi legge til en konstruktør som vist nedenfor:
klasse Punkt { offentlig : flyte x ; // Koordinater til flytepunktet og ; // Konstruktørpunkt () : x ( 0 ), y ( 0 ){ // Vi initialiserer variablene "x" og "y" } }; // Main for å demonstrere hvordan klassen fungerer # include <iostream> // Dette lar oss bruke "cout" bruker navneområde std ; int main () { Point MyPoint ; // lag et element i Point-klassen kalt MyPoint cout << "X Coordinate: " << MyPoint . x << endl ; // vis verdien akkumulert i variabelen x cout << "Y Coordinate: " << MyPoint . og << endl ; // vis verdien akkumulert i variabelen og getchar (); // fortelle programmet å vente på input buffer (stopp) returnere 0 ; }Hvis vi kompilerer og kjører programmet ovenfor, får vi en utgang som skal ligne følgende:
X-koordinat: 0 Y-koordinat: 0
Det er flere typer konstruktører i C++:
Konstruktører + Minnehaug Et objekt som er skapt på den måten vi har sett så langt, er et objekt som lever innenfor omfanget (klammer { }) der det ble opprettet. For at et objekt skal fortsette å leve når det flyttes ut av omfanget det ble opprettet i, må det opprettes i haugminnet. For dette brukes den nye operatøren, som tildeler minne for å lagre det opprettede objektet, og kaller også konstruktøren (slik at parametere kan sendes til det). Den nye operatøren brukes som følger:
int main () { Punkt * aPoint = nytt punkt (); //dette kaller konstruktøren beskrevet ovenfor delete aPoint ; //ikke glem å frigjøre minnet som er okkupert av objektet (se avsnittet om destruktorer nedenfor) return 0 ; }Med den nye []-operatoren kan du også lage arrays med dynamisk størrelse (ordnede samlinger eller lister):
Point * assign ( int quanta ) { returnere nytt punkt [ hvor mange ]; // alloker en matrise med 'hvor mange' poeng (konstruktøren vist ovenfor kalles), og returner. }Destruktorer er spesielle medlemsfunksjoner som kalles automatisk ved programkjøring, og trenger derfor ikke å bli kalt eksplisitt av programmereren . Dens hovedoppgaver er:
Destruktorer kalles automatisk når programflyten når slutten av omfanget der objektet er deklarert. Det eneste tilfellet der destruktoren til et objekt må kalles eksplisitt, er når det ble opprettet ved hjelp av den nye operatoren, det vil si at det lever i heap-minne, og ikke i programmets utførelsesstabel. Påkallingen av destruktoren til et objekt som bor i haugen gjøres gjennom delete-operatoren eller delete[] for arrays. Eksempel:
int main () { int * anHeltall = ny int ( 12 ); //vi tilordner et heltall i heap-minnet med verdien 12 int * arrayDeIntegers = new int [ 25 ]; // allokere minne for 25 heltall (de er ikke initialisert) delete anInteger ; //frigjør minnet som er okkupert av anInteger delete [] arrayOfIntegers ; //frigjør minnet som er okkupert av arrayDeIntegers return 0 ; }Hvis delete- og delete[]-operatorene ikke ble brukt i det tilfellet, ville minnet som er okkupert av henholdsvis anInteger og arrayOfIntegers, være meningsløst okkupert. Når en del av minnet er okkupert av en variabel som ikke lenger brukes, og det ikke er mulig å få tilgang til den, kalles det en "minnelekkasje". I store applikasjoner, hvis det oppstår mange minnelekkasjer, kan programmet ende opp med å ta opp mye mer RAM enn det burde, noe som ikke er praktisk i det hele tatt. Dette er grunnen til at heap memory management bør brukes bevisst.
Det er to typer destruktorer, de kan være offentlige eller private, avhengig av om de er deklarert:
Bruken av destruktorer er nøkkelen i konseptet Acquiring Resources is Initializing .
Medlemsfunksjon er en som er deklarert i klasseomfang. De ligner på de vanlige funksjonene, med unntak av at kompilatoren vil utføre Name Mangling- prosessen : Den vil endre navnet på funksjonen ved å legge til en identifikator for klassen den er deklarert i, og kan inneholde spesialtegn eller numeriske tegn. identifikatorer. Denne prosessen er usynlig for programmereren. I tillegg mottar medlemsfunksjoner implisitt en tilleggsparameter: denne pekeren , som refererer til objektet som utfører funksjonen.
Medlemsfunksjoner kalles ved først å få tilgang til objektet de refererer til, med syntaksen: myobject.mymemberfunction() , dette er et tydelig eksempel på en medlemsfunksjon.
Et spesielt tilfelle er statiske medlemsfunksjoner. Selv om de er deklarert i klassen, vil de ikke motta denne pekeren ved bruk av det statiske nøkkelordet . Takket være dette er det ikke nødvendig å opprette noen forekomst av klassen for å kalle denne funksjonen, men kun de statiske medlemmene av klassen kan nås siden disse ikke er knyttet til objektet, men med typen. Syntaksen for å kalle denne statiske funksjonen er mytype::mystaticmember() .
Maler er C++s mekanisme for å implementere det generiske programmeringsparadigmet . De lar en klasse eller funksjon jobbe med abstrakte datatyper, og spesifiserer senere hvilke som skal brukes. For eksempel er det mulig å konstruere en generisk vektor som kan inneholde hvilken som helst type datastruktur. På denne måten kan objekter i klassen til denne vektoren deklareres som inneholder heltall, flyter, polygoner, figurer, personellposter, etc.
Deklarasjonen av en mal gjøres ved å prefiksere deklarasjonsmalen <typenavn A,....> til deklarasjonen av ønsket struktur (klasse, struktur eller funksjon).
For eksempel:
mal < typenavn T > T maks ( konst T & x , konstant T & y ) { returnere ( x > y ) ? x : y ; //if x > y, returner x, ellers returnerer y }max()- funksjonen er et eksempel på generisk programmering, og gitt to parametere av en type T (som kan være int , long , float , double , etc.) vil den returnere den største av dem (ved å bruke > operatoren ). Når du utfører funksjonen med parametere av en bestemt type, vil kompilatoren prøve å "matche" malen til den datatypen, eller den vil generere en feilmelding hvis den ikke klarer det.
SpesialiseringFølgende eksempel:
mal < typenavn A > int min funksjon ( A a );oppretter en mal der alle spesialiserte funksjoner for en datatype som int myfunction(int), int myfunction(std::string), int myfunction(bool) og så videre kan defineres i overskriftskoden:
int myfunction ( int a ) { returner a + 5 ; }; int myfunction ( std :: string a ) { returner -a . _ størrelse (); }; int myfunction ( bool a ) { return ( a & rand ()); //Hvis a er sant, returner et tilfeldig tall; ellers returnerer den 0 };Hver av disse funksjonene har sin egen definisjon (kropp). Hvert forskjellige, ikke-ekvivalente ("ikke-konverterbare") organ tilsvarer en spesialisering . Hvis en av disse funksjonene ikke er definert, vil kompilatoren prøve å bruke de tillatte datatypekonverteringene for å "matche" en av malene, eller vil generere en feilmelding hvis den ikke klarer det.
Alle aktiverte definisjoner av en mal må være tilgjengelig på kompileringstidspunktet, så det er foreløpig ikke mulig å "kompilere" en mal som en objektfil, men bare å kompilere spesialiseringer av malen. Derfor distribueres malene sammen med kildekoden til applikasjonen. Det er med andre ord ikke mulig å kompilere std::vector< > malen til objektkode, men det er for eksempel mulig å kompilere en std::vector<std::string> datatype .
I C++ er det mulig å definere abstrakte klasser. En abstrakt klasse, eller abstrakt basisklasse (ABC), er en som kun er utformet som en overordnet klasse som barneklasser må avledes fra. En abstrakt klasse brukes til å representere de enhetene eller metodene som senere implementeres i avledede klasser, men selve abstraktklassen inneholder ingen implementeringer -- den representerer bare metodene som skal implementeres. Derfor er det ikke mulig å instansiere en abstrakt klasse, men det er mulig å instansiere en konkret klasse som implementerer metodene som er definert i den.
Abstrakte klasser er nyttige for å definere grensesnitt, det vil si et sett med metoder som definerer oppførselen til en gitt modul. Disse definisjonene kan brukes uavhengig av implementeringen som skal gjøres av dem.
I C++ er metodene til abstrakte klasser definert som rene virtuelle funksjoner .
klasse Abstrakt { offentlig : virtuell int metode () = 0 ; } klasse ConcreteA : offentlig abstrakt { offentlig : int () metode { //gjør noe return foo () + 2 ; } }; klasse ConcreteB : offentlig abstrakt { offentlig : int () metode { //en annen implementering return baz () - 5 ; } };I eksemplet er ConcreteA -klassen en implementering av Abstract -klassen , og ConcreteB -klassen er en annen implementering. Det bør bemerkes at = 0 er notasjonen som C++ bruker for å definere rene virtuelle funksjoner.
Et tillegg til funksjonene til C er navneområder , som kan beskrives som virtuelle områder der visse variabelnavn eller typer har gyldighet. Dette gjør det mulig å unngå at det oppstår konflikter mellom navn på funksjoner, variabler eller klasser.
Det mest kjente eksemplet i C++ er std:: namespace , som lagrer alle nye C++-definisjoner som skiller seg fra C (noen strukturer og funksjoner), samt C++s egen funksjonalitet ( streams ) og C++-komponenter. STL-bibliotek .
For eksempel:
# inkluderer <iostream> // Funksjonene i denne overskriften finnes i std:: navneområdet navneområde min_pakke { int min_verdi ; }; intmain ( ) { int min_verdi = 3 ; min_pakke :: min_verdi = 4 ; std :: cout << min_verdi << '\n' ; // skriver ut '3' std :: cout << min_pakke :: min_verdi << '\n' ; // skriv ut '4' returner 0 ; }Som du kan se, vil direkte anrop til my_value kun gi tilgang til den lokalt beskrevne variabelen; for å få tilgang til my_package navneområdevariabelen må du spesifikt få tilgang til navneområdet. En anbefalt snarvei for enkle programmer er bruk av navneområdedirektivet , som lar deg få tilgang til variabelnavnene til den ønskede pakken direkte, så lenge det ikke er noen tvetydighet eller navnekonflikt.
Det finnes flere typer arv mellom klasser i programmeringsspråket C++. Disse er:
Enkel arvArv i C++ er en abstraksjonsmekanisme laget for å lette og forbedre utformingen av klasser i et program. Med den kan du opprette nye klasser fra allerede laget klasser, så lenge de har en spesiell type relasjon.
I arv "arver" avledede klasser data og medlemsfunksjoner fra basisklasser, og avledede klasser kan omdefinere disse atferdene (polymorfisme) og legge til ny atferd som er spesifikk for avledede klasser. For ikke å bryte prinsippet om innkapsling (skjule data hvis kunnskap ikke er nødvendig for bruk av klasser), er det gitt en ny data-/funksjonssynlighetsmodus: "beskyttet". Alt med beskyttet synlighet vil oppføre seg som offentlig i Base-klassen og klasser som utgjør arvehierarkiet, og privat i klasser som IKKE er i arvehierarkiet.
Før vi bruker arv, må vi stille oss selv et spørsmål, og hvis det gir mening, kan vi prøve å bruke dette hierarkiet: Hvis uttrykket <klasseB> IS-A <klasseA> gir mening, så har vi et mulig tilfelle av arv hvor klasse A vil være basisklassen og klasse B den deriverte.
Eksempel: klasser Ship, Battleship, Freighter, etc. Et slagskip IS-A skip, et frakteskip IS-A skip, et Ocean Liner IS-A skip, etc.
I dette eksemplet vil vi ha de generelle tingene til et skip (i C++)
klasse skip { beskyttet : char * navn ; flytevekt ; _ offentlig : // Konstruktører og andre grunnleggende skipsfunksjoner };og nå kan egenskapene til de avledede klassene (mens de arver skipets) legge til ting som er spesifikke for skipsundertypen vi skal lage, for eksempel:
klasse Freighter : public Ship { // Dette er måten å spesifisere at det arver fra Ship private : flyte last ; //Resten av tingene }; klasse slagskip : offentlig skip { privat : int numberweapons ; int Soldater ; // Resten av tingene };Til slutt bør det nevnes at det er 3 arveklasser som er forskjellige i måten de håndterer synligheten til komponentene i den resulterende klassen:
Multippel arv er mekanismen som lar programmereren lage avledede klasser fra ikke bare én basisklasse, men flere. For å forstå dette bedre, la oss ta et eksempel: Når du ser hvem som besøker deg i en butikk, som person, kan du anta at han kan snakke, spise, gå, men på den annen side kan du som ansatt også anta at han har en sjef, som kan belaste deg for kjøpet, som kan gi deg vekslepenger osv. Hvis vi overfører dette til programmering vil det være multippel arv (employee_store class):
klasse Person { ... snakke (); gå (); ... }; klasse Ansatt { sjefsperson ; _ int lønn ; Charge (); ... }; klasse Butikkansatt : offentlig person , ansatt { ... StoreStock (); CheckStock (); ... };Derfor er det mulig å bruke mer enn én klasse slik at en annen klasse arver sine egenskaper.
Operatøroverbelastning er en måte å gjøre polymorfisme på . Det er mulig å definere atferden til en språkoperatør for å arbeide med brukerdefinerte datatyper. Ikke alle C++-operatører er overbelastbare, og blant de som kan overbelastes må spesielle betingelser oppfylles. Spesielt er størrelsen på og :: - operatører ikke overbelastbare.
Det er ikke mulig i C++ å opprette en ny operatør.
Atferden til overbelastede operatører implementeres på samme måte som en funksjon, bortsett fra at funksjonen vil ha et spesielt navn:Tipo de dato de devolución operator<token del operador>(parámetros)
Følgende operatører kan bli overbelastet:
Siden disse operatørene er definert for en brukerdefinert datatype, står brukeren fritt til å tilordne enhver semantikk de ønsker til dem. Det anses imidlertid som primært viktig at semantikken er så nær den naturlige oppførselen til operatørene at bruken av overbelastede operatører er intuitiv. For eksempel bør bruken av den unære operatoren - endre "tegnet" til en "verdi".
De overbelastede operatørene er fortsatt funksjoner, så de kan returnere en verdi, hvis denne verdien er av datatypen som operatøren jobber med, tillater den kjeding av utsagn. For eksempel, hvis vi har 3 variabler A, B og C av type T og vi overbelaster =-operatoren til å jobbe med datatype T, er det to alternativer: hvis operatoren ikke returnerer noe, en setning som "A=B=C ;" (uten anførselstegn) ville gi en feil, men hvis en datatype T returneres når du implementerer operatøren, vil det tillate å sette sammen så mange elementer som ønsket, slik at noe sånt som "A=B=C=D=...;"
Programmeringsspråk har ofte en rekke innebygde funksjonsbiblioteker for datamanipulering på det mest grunnleggende nivået. I C++, i tillegg til å kunne bruke C - bibliotekene , kan du bruke det opprinnelige STL (Standard Template Library), typisk for språket. Den gir en serie maler som gjør det mulig å utføre operasjoner på datalagring, input/output-behandling.
Klassene basic_ostream og basic_stream , og objektene cout og cin , gir standard datainngang og -utgang (tastatur/skjerm). Cerr er også tilgjengelig , lik cout, brukt for standard feilutgang. Disse klassene har henholdsvis << og >> operatørene overbelastet for å være nyttige for å sette inn/uttrekke data til nevnte strømmer. De er intelligente operatører, siden de er i stand til å tilpasse seg typen data de mottar, selv om vi må definere oppførselen til nevnte input/output for klasser/datatyper definert av brukeren. For eksempel:
ostream & operator << ( ostream & fs , const Dot & dot ) { returner fs << punkt . x << "," << prikk . og ; }På denne måten, for å vise et punkt, ville det bare være nødvendig å utføre følgende uttrykk:
//... Punkt p ( 4 , 5 ); //... cout << "Koordinatene er: " << p << endl ; //...Det er mulig å formatere inndata/utdata, som indikerer antall desimaler som skal vises, om tekstene skal konverteres til små eller store bokstaver, om tallene som mottas er i oktalt eller heksadesimalt format , etc.
Strømtype for filhåndtering. Den tidligere definisjonen av ostreams/istreams gjelder for denne delen. Det er tre klasser (lese, skrive eller lese/skrive filer): ifstream , ofstream og fstream .
Slik åpner du en fil: (file_variable_name).open("filnavn.dat/txt", ios::in); for å åpne den i lesemodus. (filvariabelnavn).open("filnavn.dat/txt", ios::out); for å åpne den i skrivemodus.
Eksempel: f.open("data.txt", ios::in);
Slik lukker du filen: variable_name_file.close();
Eksempel: f.close();
Les en fil:
1-Hvis det er en ren tekstfil: #include <fstream> #inkluder <streng> #include <iostream> bruker navneområde std ; int main () { ifstream input ; inngang . åpen ( "flattekst.txt" ); streng aString ; mens ( skriv inn >> aString ) cout << "Lei: " << aString << endl ; returner 0 ; } 2-Hvis det er en binær fil (.dat); file_variable_name.read((char*)&variable_name, sizeof(variable_type)); Eksempel: f.read((char*)&e, sizeof(int));Skriv en fil:
1-Hvis det er en tekstfil (.txt): variabelnavn<<"tekst"; hvor "tekst" også kan være en variabel av en hvilken som helst primitiv type, eller en streng. Eksempel: f<<HEIL; 2-Hvis det er en binær fil (.dat); file_variable_name.write((char*)&variable_name, sizeof(variable_type)); Eksempel: f.write((char*)&e, sizeof(int));De kan åpnes ved å sende parametrene knyttet til plasseringen av filen og åpningsmodusen til konstruktøren:
To klasser skiller seg ut, ostringstream og istringstream . Alt ovenfor gjelder for disse klassene. De behandler en kjede som om den var en datastrøm. ostringstream lar deg lage en tekststreng ved å sette inn data som en strøm, og istringstream kan trekke ut informasjonen i en streng (overført som en parameter i konstruktøren) med operatøren >>. Eksempler:
ostringstream s ; s << navn << "," << alder << "," << høyde << "," << punkt ( 5 , 6 ) << endl ; cout << s . str (); istringstream s ( streng ); s >> navn >> alder >> høyde >> p ;De er spesielle malklasser som brukes til å lagre generiske datatyper, uansett hva de måtte være. Alle beholdere er homogene, det vil si at når de er erklært å inneholde en bestemt datatype, i den beholderen, kan bare elementer av den typen settes inn. Avhengig av oppbevaringstypen har vi flere typer:
For å legge til elementer på slutten av vektoren, brukes push_back(const T&)-metoden. På den annen side, for å fjerne et element fra slutten av matrisen, må pop_back()-metoden brukes.
#include <vektor> //bibliotek som inneholder vektorklassen #include <iostream> bruker navneområde std ; int main () { vektor < int > intVector ; //lag en vektor av heltall (uten elementer) intVector . push_back ( 25 ); //legg til heltall 25 til vektorcout << "Det første elementet er: " << intVector . foran () << " og vektoren min har " << intVector . størrelse () << " elementer." << endl ; //skriv ut det første elementet, returnert av front()-metoden intVector . push_back ( 32 ); //legg til heltall 32 til vektorcout << "Det første elementet er: " << intVector [ 0 ] << endl ; //print 25 intVector . pop_back (); //fjern det siste elementet i vektoren (dvs. 32) cout << "Nå har jeg: " << intVector . størrelse () << " elementer." << endl ; // vil skrive ut 1 returner 0 ; }I tillegg til metodene push_back(const T&) og pop_back() legges metodene push_front(const T&) og pop_front() til, som gjør det samme som de som allerede er forklart, men i begynnelsen av køen.
#include <deque> //deque-bibliotek bruker navneområde std ; int main () { deque < int > intDeque ; intDeque . push_front ( 25 ); intDeque . push_back ( 12 ); while ( intDeque.size ( ) ) intDeque . pop_back (); //slett alle elementer returner 0 ; }De kan betraktes som en generalisering av "peker"-klassen. En iterator er en datatype som gjør det mulig å krysse og søke etter elementer i beholdere. Siden datastrukturene (beholderne) er generiske klasser, og operatørene (algoritmene) som må operere på dem også er generiske (generiske funksjoner), måtte Stepanov og hans samarbeidspartnere utvikle konseptet om iteratoren som et element eller kobling mellom de to ... Det nye konseptet viser seg å være en slags pekere som peker på de ulike medlemmene av beholderen (generiske pekere som som sådan ikke finnes i språket).
Ved å kombinere bruken av maler og en spesifikk stil for å betegne typer og variabler, tilbyr STL en rekke funksjoner som representerer vanlige operasjoner, og hvis mål er å "parametrisere" operasjonene som disse funksjonene er involvert i, slik at deres lesing, forståelse og vedlikehold, er lettere å utføre.
Et eksempel er kopifunksjonen , som ganske enkelt kopierer variabler fra ett sted til et annet. Mer strengt kopierer den innholdet hvis plassering er avgrenset av to iteratorer, til plassen indikert av en tredje iterator. Syntaksen er:
kopi (kildestart, kildeslutt, målstart);På denne måten kopieres alle dataene mellom kildestart og kildeslutt, unntatt dataene som ligger i sistnevnte, til et sted beskrevet eller pekt på av destination_start.
En veldig viktig algoritme som er implementert i STL-biblioteket er typen. Sorteringsalgoritmen sorterer alle typer beholdere, så lenge de sendes som argumenter, fra hvor og til hvor du vil sortere den.
#inkluder <vektor> #include <deque> #include <algoritme> int main () { vektor < int > intVector ; intVector . push_back ( 60 ); intVector . push_back ( 12 ); intVector . push_back ( 54 ); //for dette øyeblikket har vektoren 60,12,54 sort ( intVector . begin (), intVector . end ()); //ferdig, bestilt array, nå har den 12,54,60 /*Merk at hvis det i stedet for en vektor var en deque, ville den bli bestilt på samme måte. */ }Populære funksjoner inkluderer swap (variabel1, variabel2) , som ganske enkelt bytter verdiene til variabel1 og variabel2; max (variabel1, variabel2) og dens likhet min (variabel1, variabel2) , som returnerer maksimum eller minimum mellom to verdier; find(start, end, value) som ser etter verdi i variabelrommet mellom start og slutt; og så videre.
Algoritmene er veldig varierte, noen har til og med spesifikke versjoner for å operere med visse iteratorer eller beholdere, og gir et ekstra abstraksjonsnivå som gjør det mulig å få en "renere" kode, som "beskriver" hva som blir gjort, i stedet for å gjøre det trinn for trinn eksplisitt.
Den 12. august 2011 rapporterte Herb Sutter, leder av C++-standardkomiteen, den enstemmige godkjenningen av den nye standarden. [ 3 ] Publiseringen av den ble gjort en gang i 2011.
Blant egenskapene til den nye standarden kan følgende fremheves:
I tillegg er standardspråkbiblioteket oppdatert .
I 2011 innledet C++11 en ny æra i C++-historien, og startet en tre-års syklus med nye versjonsutgivelser. C++11 ble fulgt av C++14 og deretter C++17 , som er gjeldende versjon fra 2019; C++20 er nær standardisering, og arbeidet med C++23-versjonen er allerede i gang. Kompilatorer prøver å komme seg i forkant ved å eksperimentelt innlemme noen nye funksjoner før offisielle utgivelser. Men hver nye versjon av C++ inkluderer så mange tillegg at avanserte kompilatorer ofte ikke blir ferdige med å innlemme dem før to eller tre år etter utgivelsen av den versjonen.
I C++ konverteres enhver datatype som er erklært fullt kvalifisert til en enkelt datatype. Betingelsene for at en datatype T skal erklæres fullstendig er omtrent følgende:
Generelt betyr dette at enhver datatype som er definert med fulle overskrifter, er en fullstendig datatype.
Spesielt, og i motsetning til i C, er typer definert via struct eller enum fulltyper . Som sådan er de nå utsatt for overbelastning, implisitte konverteringer og så videre.
Oppregnede typer er derfor ikke lenger bare aliaser for heltallstyper, men er unike datatyper i C++. Bool -datatypen er tilfeldigvis også en enkelt datatype, mens den i C i noen tilfeller fungerte som et alias for en heltallsdataklasse.
En av de gratis C++-kompilatorene er GNU - kompilatoren, G++- kompilatoren (en del av GCC -prosjektet , som omfatter flere kompilatorer for forskjellige språk). Andre vanlige kompilatorer inkluderer Intel C++ Compiler , Xcode Compiler, Borland C++ Compiler, CodeWarrior C++ Compiler, Cygwin g++ Compiler, MinGW g++ Compiler, Visual C++ Compiler , Carbide.c++ og andre.
Til tross for dets utbredte bruk, har C++-språket blitt kritisert av mange programmerere, inkludert Linus Torvalds , [ 4 ] Richard Stallman , [ 5 ] og Ken Thompson . [ 6 ] Problemer inkluderer mangel på refleksjon eller søppeloppsamler , langsomme kompileringstider, oppfattet funksjonskryp , [ 7 ] og detaljerte feilmeldinger, spesielt fra mal-metaprogrammering. [ 8 ]
For å unngå problemene som finnes i C++, og for å øke produktiviteten, [ 9 ] foreslår noen alternative språk nyere enn C++, som D , Go , Rust og Vala . [ 10 ]