C++

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.

C++-funksjoner

Eksempler

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.

Datatyper

C++ har følgende grunnleggende typer :

  • Tegn: char(også et heltall),wchar_t
  • Heltall: short, int, long,long long
  • Flytende kommatall: float, double,long double
  • boolske:bool
  • Tømme:void

Modifikatoren unsignedkan brukes på heltall for å få usignerte tall (heltall er fortegnet som standard), og dermed oppnå et større utvalg av naturlige tall.

Tilknyttede størrelser

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 .

Størrelser på primitive typer under i386 (GCC)
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":

  • I henhold til C99 -standarden må en type charoppta nøyaktig én byte som består av minimum 8 biter uavhengig av maskinarkitekturen.
  • Den gjenkjente størrelsen på charer 1. Det vil si sizeof(char)at den alltid returnerer 1.
  • En type shorthar minst samme størrelse som en type char.
  • En type longer minst dobbelt så stor i byte av en type short.
  • En type inthar en størrelse mellom shortog og longinklusive, fortrinnsvis størrelsen på en maskinminnepeker. Dens maksimale verdi er 2147483647, med 32 biter.
  • En type unsignedhar samme størrelse som versjonen signed.

Wchar_t

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:

  • strcpy - wstrcpy
  • std::string - std::wstring
  • std::cout - std::wcout

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 "void"

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 feil

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

Ordet "NULL"

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

Prinsipper

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.

Konseptet med klasse

Se også: Klasse (datavitenskap)

Objekter i C++ abstraheres av en klasse. I følge det objektorienterte programmeringsparadigmet består et objekt av:

  1. Identitet, som skiller den fra andre objekter (navn som klassen som objektet tilhører vil bære).
  2. Medlemsmetoder eller funksjoner.
  3. Attributter eller medlemsvariabler.

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

Byggherrer

Se også: Konstruktør (informatikk)

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++:

  1. standard konstruktør . Det er konstruktøren som ikke mottar noen parametere i funksjonen. Hvis ingen konstruktør ble definert, ville systemet gi en standard. Det er nødvendig for konstruksjon av strukturer og containere til STL.
  2. Kopier Builder . Det er en konstruktør som mottar et objekt av samme klasse, og lager en kopi av dets attributter. Som standard, hvis ikke definert, leveres en av systemet.
  3. Konverteringsbygger . Denne konstruktøren mottar som sin eneste parameter et objekt eller variabel av en annen type enn sin egen. Det vil si at den konverterer et objekt av en bestemt type til et annet objekt av typen vi genererer.

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

Destroyers

Se også: Destructor (databehandling)

Destruktorer er spesielle medlemsfunksjoner som kalles automatisk ved programkjøring, og trenger derfor ikke å bli kalt eksplisitt av programmereren . Dens hovedoppgaver er:

  • Slipp beregningsressursene som objektet til den klassen har skaffet seg ved kjøretid når den utløper.
  • Fjern koblingene som andre ressurser eller objekter kan ha med denne.

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:

  • Hvis den er offentlig, kalles den opp fra hvor som helst i programmet for å ødelegge objektet.
  • Hvis det er privat, er det ikke tillatt å ødelegge objektet av brukeren.

Bruken av destruktorer er nøkkelen i konseptet Acquiring Resources is Initializing .

Medlemsfunksjoner

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

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.

Spesialisering

Fø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 .

Abstrakte klasser

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.

Navneområder

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.

Arv

Det finnes flere typer arv mellom klasser i programmeringsspråket C++. Disse er:

Enkel arv

Arv 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:

  • Offentlig arv (klasse Avledet: offentlig Base ): Med denne typen arv respekteres den opprinnelige oppførselen til synlighetene til Base-klassen i Avledet-klassen.
  • Privat arv (Avledet klasse: privat Base): Med denne typen arv vil hver komponent av Base-klassen være privat i Avledet-klassen (arvede egenskaper vil være private selv om de er offentlige i Base-klassen)
  • Beskyttet arv (Avledet klasse: beskyttet Base): Med denne typen arv vil alle offentlige og beskyttede komponenter i Base-klassen være beskyttet i Avledet-klassen, og private komponenter forblir private.
Multippel arv

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 (); (); ... }; 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ør overbelastning

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:

  • Unære operatører
    • Operatør * (for indirektion)
    • Operatør -> (for indirektion)
    • & (adresse) operatør
    • Operatør +
    • Operatør -
    • operatør ++
    • Operatør --
  • Binære handelsmenn
    • Operatør ==
    • Operatør +
    • Operatør -
    • Operatør *
    • Operatør /
    • Operatør %
    • Operatør <<
    • Operatør >>
    • Operatør &
    • operatør ^
    • Operatør |
    • Operatør []
    • operatør()
  • Oppdragsoperatører
    • Operatør =
    • Operatør +=
    • Operatør -=
    • Operatør *=
    • Operatør /=
    • Operatør %=
    • Operatør <<=
    • Operatør >>=
    • &= operatør
    • ^= operatør
    • Operatør |=

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=...;"

Standard malbibliotek (STL)

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.

Inndata- og utdatabibliotek

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.

Fstreams

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:

Strømmer

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 ;

Beholdere

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:

  • Vektorer: De er definert avvektor<datatype> vektornavn;De er arrays (eller ordnede lister) som automatisk endres størrelse når nye elementer legges til, slik at "teoretisk" uendelige elementer kan legges til. Vektorer lar oss få tilgang til ethvert element de inneholder, ved å bruke []-operatoren. Merk at hvis du prøver å få tilgang til en posisjon som overskrider grensene til vektoren, vil vektoren ikke foreta noen kontroller, så du må være forsiktig når du bruker denne operatoren. For å sikre sikker tilgang til matrisen kan at(int)-metoden brukes, som kaster et unntak av typen std::out_of_range hvis dette skjer.

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 ; }
  • Doble haler: Disse ligner på vektorer, men har bedre effektivitet for å legge til eller fjerne elementer ved "tuppene".deque<data_type> kønavn;

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 ; }
  • Lister: De er effektive når det gjelder å legge til elementer. Forskjellen med doble køer er at de er mer effektive for å eliminere elementer som ikke er i en av "tipsene"liste<datatype> listenavn;
  • Sekvensadaptere.
  • Assosiative beholdere: kart og multimap, som gjør det mulig å knytte en "nøkkel" til en "verdi". map tillater ikke gjentatte verdier, mens multimap gjør det.
kart<nøkkeltype, datatype> kartnavn; multimap<nøkkeltype, datatype> multimap_name; #include <map> //bibliotek som inneholder kart og multimap #include <string> //strengbibliotek #include <iostream> //input/output-bibliotek bruker navneområde std ; int main () { map < int , string > intAString ; intAString [ 1 ] = "en" ; intAString [ 10 ] = "ti" ; cout << "I intAString[1]: " << intAString [ 1 ] << endl ; cout << "I intAString[10]: " << intAString [ 10 ] << endl ; returner 0 ; }
  • Assosiative beholdere: sett og multisett, som bare tilbyr betingelsen om å "tilhøre", uten at det er nødvendig å garantere en spesiell rekkefølge av elementene de inneholder.

Iteratorer

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

Algoritmer

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.

C++11

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:

  • lambdafunksjoner ; _
  • rvalue referanser;
  • Auto nøkkelordet ;
  • Ensartet initialisering;
  • Maler med variabelt antall argumenter.

I tillegg er standardspråkbiblioteket oppdatert .

Nåtid og fremtid

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.

Typeforskjeller fra C

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:

  • Det er mulig på kompileringstidspunktet å kjenne plassen knyttet til datatypen (det vil si at kompilatoren må kjenne resultatet av sizeof(T) ).
  • T Har minst én godt erklært konstruktør og destruktor .
  • Hvis T er en sammensatt type, eller er en avledet klasse, eller er en malspesifikasjon, eller en kombinasjon av det ovenfor, må de to betingelsene nevnt ovenfor gjelde for hver datatype.

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.

Kompilatorer

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.

Utviklingsmiljøer

Se også: Integrert utviklingsmiljø

Under Microsoft Windows

Under MacOS

Under DOS

Under GNU/Linux

Programvare opprettet og programmert med C++

Kritikk

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 ]

Se også

Referanser

  1. https://www.iso.org/standard/68564.html
  2. Stroustrup, Bjarne (1997). "1" . C++-programmeringsspråket (tredje utgave). ISBN  0201889544 . OCLC  59193992 . Hentet 25. februar 2010 . 
  3. http://herbsutter.com/2011/08/12/we-have-an-international-standard-c0x-is-unanimously-approved/
  4. ^ " Re: [RFC Convert builin-mailinfo.c to use The Better String Library]", 6. september 2007 , https://lwn.net/Articles/249460/ , hentet 31. mars 2015 . 
  5. « Re: Innsats for å tiltrekke flere brukere? », 12. juli 2010 , http://harmful.cat-v.org/software/c++/rms , åpnet 31. mars 2015 . 
  6.  
  7. ^ Pike, Rob (2012). "Mindre er eksponentielt mer" . 
  8. Kerinin, Yossi (13. oktober 2009). "Defekt C++" . Hentet 3. februar 2016 . 
  9. Nye språk, og hvorfor vi trenger dem , MIT Technology Review
  10. De nye morsmålene | Dr dobbs

Bibliografi

  • Bjarne Stroustrup , The C++ Programming Language , Addison Wesley , Madrid, 1998, ISBN 84-7829-019-2
  • Bjarne Stroustrup, The C++ Programming Language , Addison-Wesley Pub Co; Tredje utgave (15. februar 2000); ISBN 0-201-70073-5
  • Bjarne Stroustrup, The Design and Evolution of C++ , Addison-Wesley Pub Cp; Første utgave (29. mars 1994); ISBN 0-201-54330-3
  • Margaret A. Ellis og Bjarne Stroustrup, The Annotated C++ Reference Manual , Addison-Wesley Pub Co; (1. januar 1990); ISBN 0-201-51459-1

Eksterne lenker