A C++ (ejtsd: cé plusz plusz) egy általános célú, magas szintű programozási nyelv. Támogatja a procedurális, az objektumorientált és a generikus programozást, valamint az adatabsztrakciót. Napjainkban szinte minden operációs rendszer alá létezik C++ fordító. A nyelv a C programozási nyelv hatékonyságának megőrzése mellett törekszik a könnyebben megírható, karbantartható és újrahasznosítható kód írására, ez azonban sok kompromisszummal jár, erre utal, hogy általánosan elterjedt a mid-level minősítése is, bár szigorú értelemben véve egyértelműen magas szintű.
Története jobbra|bélyegkép|250px|Bjarne Stroustrup Bjarne Stroustrup kezdte el a C++ programozási nyelv fejlesztését a C programozási nyelv kiterjesztéseként, más nyelvekből véve át megoldásokat (Simula67, Algol68), ötleteket (ADA). A nyelv első, nem kísérleti körülmények közt való használatára 1983-ban került sor, 1987-ben pedig nyilvánvalóvá vált, hogy a C++ szabványosítása elkerülhetetlen. Ez a folyamat 1991 júniusában kezdődött el, amikor az ISO szabványosítási kezdeményezés részévé vált. A C++ programozási nyelv szabványát 1998-ban hagyták jóvá ISO/IEC 14882:1998 néven, az aktuális, 2017-es változat kódjelzése ISO/IEC 14882:2017.
Érdekesség Mire a nyelvet szabványosították, már rengeteg C++ nyelvű kód készült, került használatba. Mivel a szabvány fejállományok némileg eltértek az eddigiektől, a bizottság érdekes megoldást választott a C és C++ kompatibilitás megtartására: A régi C++ fejállományok (pl. „iostream.h”) továbbra is használhatóak (bár hivatalosan nem támogatottak), de tartalmuk nincs benne a standard névtérben. Az új, hivatalos fejállományok („iostream”) szinte megegyeznek a régiekkel, de tartalmuk a standard névtérben szerepel. A szabvány C fejállományok (pl.: „stdio.h”) továbbra is támogatottak, de tartalmuk a globális névtérben van. A C könyvtárak átvétele szintén a .h eltávolításával történt, beszúrva egy c-t a nevük elé (pl. „stdio.h”-ból „cstdio” lett). Tartalmuk a standard névtérben szerepel.
Fordítók, fejlesztőeszközök Windows operációs rendszeren tanuláshoz megfelelő – és ingyenes – eszköz a Code::Blocks. Haladó szinten kényelmes választás a Visual C++ Express Edition, amely ingyen letölthető a Microsoft oldaláról, de több helyen bevallottan eltér a szabványtól.
Linux/UNIX alatt fordításra a GNU Compiler Collection g++ programja áll rendelkezésre (Windows alatt is elérhető), illetve grafikus fejlesztőeszközként a KDevelop is, illetve a Code::Blocks is elérhető.
A legtöbb fordító – ha nem adjuk meg külön – néhány esetben eltér a szabványtól, így optimalizáltabb kódot hozhatnak létre. Természetesen minden esetben lehetőség van a szabvány szerinti fordításra.
A név eredete Nevét Rick Mascitti találta ki. A C++ név kifejezi, hogy a nyelv a C kibővítése: az inkrementáló operátorra utal a ++.
A C++ alapelemei Jelkészlet A kis- és nagybetűs angol ABC, általános írásjelek és a matematikai operátorok, jelek.
Azonosítók A nyelv bizonyos összetevőire (változók, konstansok, függvények stb.) névvel hivatkozunk. A legtöbb fordító csak az első 32 karaktert veszi figyelembe a nevekben. A név első karaktere betű vagy aláhúzásjel (_) lehet, ettől kezdődően már számok is szerepelhetnek benne. Lehetőleg saját névként ne adjunk meg aláhúzásjellel (_) kezdődő nevet, mert ezek a fordító számára vannak fenntartva (pl. __DATE__, __cplusplus, _MSC_VER). A C++ különbséget tesz a kis- és nagybetűk között (case-sensitive). Az alma név nem ugyanaz, mint az Alma név.
Kulcsszavak Ezek a kifejezések a nyelv részei, önmagukban nem használhatóak névként.
asm delete goto reinterpret_cast try auto do if return typedef bool double inline short typeid break dynamic_cast int signed typename case else long sizeof union catch enum mutable static unsigned char explicit namespace static_cast using class export new struct virtual const extern operator switch void const_cast false private template volatile continue float protected this wchar_tdecltype for public throw while default friend register true
Megjegyzések A megjegyzések olyan karaktersorozatok, amelyeket a program dokumentálása érdekében használunk. A fordító nem veszi figyelembe a programban elhelyezett megjegyzéseket.
// egysoros megjegyzés
/* Itt kezdődik a többsoros megjegyzés és itt a vége */
Operátorok
A C++-ban nem vezethetünk be új operátorokat, de majdnem mindegyiket túlterhelhetjük. Van infix, prefix és postfix jelölésű operátor is. Általában meghatározott számú operandusuk lehet (egy, kettő vagy három), kivéve a függvényhívás operátor (operator()), amelynek bármennyi operandusa lehet.
Precedencia Az elsőbbségi (precedencia-) szabályok a kifejezések kiértékelésének helyes sorrendjét írják elő. A kiértékelés során először mindig a magasabb precedenciájú kifejezés értékelődik először.
+ Az operátorok összefoglalása Precedencia Operátor Rövid leírás Kiértékelés iránya 1 :: Hatókör-operátor nincs 2 () [] -> . ++ -- Függvényhívás Tömbindexelés Mutatón keresztüli tag-elérés Objektumon keresztüli tag-elérés Posztfix növelés Posztfix csökkentés Balról jobbra 3 ! ~ ++ -- - + * & (típus) sizeof Logikai tagadás Bitenkénti negálás Prefix növelés Prefix csökkentés Negatív előjel Pozitív előjel Dereferálás Címképzés Konverzió típusra Méret lekérdezése Jobbról balra 4 ->* .* Tagkiválasztás mutatón Tagkiválasztás objektumon Balról jobbra 5, 6 * / % +- Szorzás Osztás Maradékszámítás Összeadás Kivonás Balról jobbra 7 << >> Bitenkénti eltolás balra Bitenkénti eltolás jobbra Balról jobbra8, 9< <= > >= !=== Kisebb Kisebb-egyenlő Nagyobb Nagyobb-egyenlőNem egyenlőEgyenlőBalról jobbra10 & Bitenkénti ÉS Balról jobbra11 ^ Bitenkénti kizáró VAGY Balról jobbra12 | Bitenkénti megengedő VAGY Balról jobbra13 && Logikai ÉS Balról jobbra14 || Logikai megengedő VAGY Balról jobbra15 ?: feltételes (if-then-else) operátor Jobbról balra16 = += -= *= /= %= &= ^= |= <<= >>= Értékadás Összeadás és értékadás Kivonás és értékadás Szorzás és értékadás Osztás és értékadás Maradékképzés és értékadás Bitenkénti ÉS és értékadás Bitenkénti kizáró VAGY és értékadás Bitenkénti megengedő VAGY és értékadás Eltolás balra és értékadás Eltolás jobbra és értékadás Jobbról balra 17 , Szekvenciaoperátor Balról jobbra
Operátorok túlterhelése A közönséges függvényekhez hasonlóan a legtöbb operátort is túl lehet terhelni, ami a felhasználói típusok kényelmesebb, szabványosabb használatát teszi lehetővé, aritmetikai operátorokkal (+, +=), és az std::cout-hoz való << operátorral.
struct Complex { //Barátfüggvény deklarációja, hogy hozzáférjen a tagokhoz friend std::ostream& operator<<(std::ostream& stream, const Complex& z);
//Konstruktor, taginicializációs listával Complex(double a, double b): re(a), im(b) { }
Complex& operator+=(const Complex& rhs) {//hozzáadó operátor tagfüggvény... re += rhs.re; im += rhs.im; return *this;
private: double re, im;
Complex operator+(const Complex& lhs, const Complex& rhs) {//összeadó operátor viszont globális return Complex(lhs) += rhs; }
//az ostream definíciójához nem férünk hozzá, de //operator<<(ostream&, const complex&)-t definiálhatunk std::ostream& operator<<(std::ostream& stream, const Complex& z) { return (stream << '(' << z.re << ", " << z.im << ')'); }
//Ezután az operátort egyszerűen használhatjuk: Complex c(1.0, 4.6); std::cout << c; //A kimeneten megjelenik: (1.0, 4.6)
Típusok, változók, konstansok A C++ -ban minden felhasznált névről meg kell mondanunk, hogy mi az, amit képvisel, tudatnunk kell a fordítóprogrammal a típusát. Megkülönböztetünk egyszerű és összetett típusokat. Egyszerű típusok az egész típusok (előjeles és előjel nélküli), a lebegőpontos típusok, a karaktertípusok, a bool és a void. Összetett típusok az alaptípusok felhasználásával felépített tömb-, mutató- stb. típusok és a felhasználói típusok (pl. osztály).
Az alapvető adattípusok mérete fordító- és platformfüggő, de a következők adottak:
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) 1 <= sizeof(bool) <= sizeof(long) sizeof(char) <= sizeof(wchar_t) <= sizeof(long) sizeof(float) <= sizeof(double) <= sizeof(long double) sizeof(N) == sizeof(signed N) == sizeof(unsigned N) (ahol N lehet char, short, int vagy long)
Az itt megadott méretek a „megszokott” 32 bites asztali környezetben általánosak, de nem garantáltak.
AdattípusÉrtékkészletMéret (bájt)Pontosság bool false, true 1 char -128..127 1 signed char -128..127 1 unsigned char 0..255 1 wchar_t 0..65535 2 int -2147483648..2147483647 4 unsigned int 0..4294967295 4 short -32768..32767 2 unsigned short 0..65535 2 long -2147483648..2147483647 4 unsigned long 0..4294967295 4 long long -9223372036854775808..9223372036854775807 8 unsigned long long 0..18446744073709551615 8 float 3.4E-38..3.8E+38 4 6 double 1.7E-308..1.7E+308 8 15 long double 3.4E-4932..3.4E+4932 1218
A memóriában létrehozott tárolókat névvel látjuk el, amelynek segítségével hivatkozhatunk rájuk. Ezeket a tárolókat változóknak nevezzük.
Konstansoknak azokat a változókat nevezzük, amelyeknek pontosan egyszer, a definícióban adhatunk értéket (ekkor kötelező), és ezt a típusnév elé vagy mögé írt const típusminősítővel jelezzük:
const int x; //Hiba! const int y = 10; //Jó y = 10; //Hiba!
A felsorolt típus (enum) Az „enum” olyan adattípust jelöl, melynek lehetséges értékei egy konstanshalmazból kerülnek ki.
enum Animals {bear, wolf, rabbit};
A fordító balról jobbra haladva nullával kezdve egész értékeket feleltet meg a felsorolt konstansoknak. Ha egy konstansnak egész értéket adunk, akkor a következő elemek ettől a kiindulási értéktől kapnak értéket.
enum Animals {bear = 10, wolf, rabbit}; //wolf és rabbit értéke rendre 11 és 12
A felsorolásban azonos értékek is szerepelhetnek. A deklarációban megadott név típusnévként is felhasználható:
enum Animals {bear, wolf, rabbit}; Animals x = bear;
Típuskonverziók Előfordulhat, hogy valamely kétoperandusú operátor különböző típusú operandusokkal rendelkezik. Ekkor, beépített típusok esetén, hogy a művelet elvégezhető legyen, a fordítónak azonos típusra kell alakítania az operandusokat. Megkülönböztetünk implicit és explicit típuskonverziót.
Implicit típuskonverzió: Ez a fajta konverzió a programozó beavatkozása nélkül automatikusan megy végbe, a C++ definíciójában szereplő szabályok alapján. A „szűkebb” típus adatvesztés nélkül konvertálódik a „szélesebb” típusra, ha szükséges.
int x = 10; float f = 1.23; x + f; //A kifejezés float típusú lesz, 10.00 + 1.23 alakban értékelődik ki Ebben az esetben adatvesztés léphet fel:
float f = 1.23; int x = f; //x értéke 1 lesz, a törtrész elvész
Explicit típuskonverzió
Feltétel nélküli típusátalakítás:
(típusnév)kifejezés (pl.: (char *)c)
Ideiglenes érték létrehozása:
típusnév(kifejezés) (pl.: int(x))
Explicit konverziót a programozó előírhat a típuskonverziós operátorok használatával is.
Dinamikus típusátalakítás:
dynamic_cast<típus>(ptr)
Futásidejű konverziókat végezhetünk vele. A típus osztályra mutató pointer, referencia, vagy void* típusú kifejezés, míg a ptr pointer vagy referencia típusú kifejezés lehet (a típusnak megfelelően). Ha a konverzió nem végezhető el, akkor pointerek esetén 0 lesz az eredmény, referenciáknál pedig bad_cast kivételt vált ki.
Fordítási idejű átalakítások:
static_cast <típus>(arg)
Visszafordítható típuskonverzió egymásba konvertálható típusok között. A típusnak és arg típusának fordítási időben ismertnek kell lennie.
reinterpret_cast<típus>(arg)
Úgy, mint a (típus)arg kifejezés, csak a reinterpret_cast nem használható const vagy volatile minősítés megszüntetésére.
Konstans típusátalakítás:
const_cast<típus>(arg)
Akkor használjuk, ha fel akarjuk oldani a const vagy volatile típusmódosítók hatását egy adott mutatón vagy referencián. A típus és arg típusának azonosnak kell lennie, kivéve a fent említett típusmódosítókat.
Pointerek
Amikor egy változót definiálunk, a memóriában létrejön egy megfelelő méretű tároló, amelybe bemásolódik a kezdőérték.
int * p;