C++ kialakulása, nem OO újdonságok
Szeberényi Imre, Somogyi Péter BME IIT szebi@iit.bme.hu
deklarációk és utasítások vegyesen
//
megjegyzés, const
, enum
, inline
változó hosszúságú tömb (függvényben)
long long
, double _Complex
)Pontosabb specifikáció pl.:
-3 / 5 == 0
-3 % 5 == -3
, C89-ben lehetne -1
és +2
(a+++b)
Nem feltétlenül kell haragudni a break
-re és a continue
-ra! Óra végén látni fogjuk, hogy C++-ban még a „goto
”-t is gyakran használjuk (bár nem így hívjuk).
Mi történik, ha x > 2.3
?
Javítva:
Makrókat kerüljük, ha lehet
Javítva:
Memóriafoglalás: ki foglal és ki szabadít?
enum
.Kódolási stílus betartása.
A lényeg a következetességen van!
int a; float alma;
int fv(int x);
- nem definícióA típus nem hagyható el!
extern int error;
extern int error;
Definíció csak egy!
int y = 12; //...
int z = 3; // és egyből inicializáljuk
for (int i = 0; i < 10; i++) {
z += i;
int k = i - 1;
y *= k; //élettartam, hatókör u.a, mint a C-ben
}
// i és k itt már nem léteznek !
const
, enum
, inline
).Hivatkozás (más néven referencia, reference), cím szerinti paraméterátadás.
new
, delete
).Változó definíció bárhol, ahol utasítás lehet.
bool
false
true
bool
automatikus típuskonverzió, ahogyan a C-ben megszoktuk.helyett:
const
: Típusmódosító, amely megtiltja az objektum átírását (a fordító nem engedi, hogy balértékként szerepeljen).
Mutatók esetén:
const char *p; // p által címzett terület nem módosítható
char const *p; // ua.
char *const q; // q-t nem lehet megváltoztatni
// ^~
// = 0
// error: default initialization of an object
// of const type 'char *const'
első kísérlet:
fordítási hiba:
error: cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'
int *px = &x;
^ ~~
1 error generated.
másdodik kísérlet:
fordítási hiba:
error: no matching function for call to 'f'
f(&x);
^
note: candidate function not viable: 1st argument ('const int *') would lose const qualifier
void f(int *i) { *i = 4; }
^
1 error generated.
Szigorúbb ellenőrzés, mint az ANSI C-ben. Pl.:
Szinek jelzo;
jelzo = 4; // fordítási hiba
// ^
// error: assigning to 'Szinek' from incompatible type 'int'
jelzo = Szinek(8); // nincs hiba, de meghatározatlan
// ^ érték létrehozása
Előrehivatkozáskor kötelező.
$ man 3 sqrt
NAME
sqrt, sqrtf, sqrtl - square root function
SYNOPSIS
#include <math.h>
double sqrt(double x);
[...]
Link with -lm.
Minden változó és függvény memóriában levő helye (címe) képezhető (pl: &valtozo
)
Ez a cím ún. mutatóban (pointerben) tárolható.
A mutató egy olyan típus, amelynek az értékkészlete cím, és mindig egy meghatározott típusú objektumra mutat.
A paraméter címe adódik át, így annak tartalma felhasználható, de meg is változtatható.
A hivatkozás (referencia) egy alternatív név (álnév, alias): tipus&
int i = 1;
int &r = i; // kötelező inicializálni, mert
// tudni kell, hogy kinek az alternatív neve
int x = r; // x = 1;
r = 2; // i = 2;
C:
C++:
// két érték felcserélése
// Változó paraméter pointerrel
void csere(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int x, y;
csere(&x, &y);
}
// két érték felcserélése
// Változó paraméter referenciával
void csere(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
int main() {
int x, y;
csere(x, y);
}
struct
&
*
Pointer paraméter és a változtatandó paraméter szétválik.
Mutató, hivatkozás + const
használatával a hozzáférés jól szabályozható:
Konvertert írunk, ami tetszőleges számrendszerbe tud konvertálni. A fv. a számrendszer alapját paraméterként kapja:
Csak az argumentumlista végén lehetnek default
argumentumok, akár több is.
f(), f(void)
- nincs paraméterf(...)
- nem kell ellenőriznif(int a, int)
- nem fogjuk használniinline int max(int a, int b) { return (a > b ? a : b); }
int main() {
int x = 3, y = 4, z;
z = max(x++, y++);
// a hívás helyére beépül a kód, miközben
// fv. hívás szabályai érvényesülnek
z = a > b ? a : b; // a = 3, b = 4
// ^ optimalizáló ezen még optimalizálhat
// Eredmény:
// x -> 4, y -> 5, z -> 4
}
int max(int a, int b) { return (a > b ? a : b); }
double max(double a, double b) { return (a > b ? a : b); }
int main() {
// Azt a változaot használja,
// ami illeszkedik a hívásra
int x = max(1, 2);
double f = max(1.2, 0.2);
}
Túlterhelt (overloaded) függvények: azonos a nevük, de eltér a paraméterlista (szignatúra), ami alapján illesztődik. Típusbiztonságot támogatja.
Érdekesség: A C++ szabvány lábjegyzetben jegyzi meg, hogy a függvény visszatérési típusa nem része a függvény szignatúrájának, azaz ez alapján nem lehet túlterhelni a függvényt! Más nyelvek másként viselkedhetnek!
C-ben ezt írtuk:
C++-ban ezt kell:
Kinek jó ez ?
printf
, scanf
nem biztonságos! Nem lehet ellenőrizni a paraméterek típusát.printf
, scanf
nem bővíthető új típussal.sync_with_stdio()
)<<
és >>
operatorok túlterhelése (overload).std::cout
egy std::ostream
típusú objektum, amihez léteznek.std::ostream &operator<<(std::ostream &os, int i);
std::ostream &operator<<(std::ostream &os, double d);
std::ostream &operator<<(std::ostream &os, const char *p);
… alakú függvények. (Később pontosítjuk)
#include <iostream>
int main() { std::cout << "Hello C++" << std::endl; }
// ^
// ostream& operator<< (ostream& os, const char* s);
// alakra illeszkedik. Bal oldalon van a függvény?
}
Referencia értékű függvény lehet bal oldalon is.
#include <iostream>
int x; // ronda globális!
int &f1() { return x; }
double &f2(double &d) { return d; }
// ^ Referenciát, azaz alternatív
// nevet szolgáltatnak
int main() {
f1() = 5;
f1()++;
double y = 0.1;
f2(y) *= 100;
std::cout << "x=" << x << " y=" << y << std::endl;
} // kiírás: x=6 y=10
// Fájl: nagyobb_main.cpp
#include <iostream>
// fv prototípusok, konstansok, típusok, egyéb deklarációk:
#include "fuggvenyeim"
using namespace std;
int main() {
cout << "Kerek ket egesz szamot:" << endl;
int i, j;
cin >> i >> j; // i és j értékének beolvasása
int k = max(i, j);
cout << "A nagyobb: " << k << endl; // nagyobb kiírása
}
// Fájl: fuggvenyeim.cpp
// Ebben valósítom meg a gyakran használt függvényeket.
// Saját header-t is célszerű behúzni ellenőrzés miatt:
#include "fuggvenyeim"
// Két int adat felcserélése
void csere(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
// ....
// Fájl: fuggvenyeim
// Ebben találhatók a függvények prototípusai, típusok...
#ifndef FUGGVENYEIM // Egy fordítási egységben
#define FUGGVENYEIM 1 // csak egyszer
/* csere
* Két int adat felcserélése // Automatikus dok. generálás
* @param a - egyik adat
* @param b - másik adat
*/
void csere(int &a, int &b); // Függvény prototípusa
/*
* max
* Két int adat közül a nagyobb
* @param a - egyik adat
* @param b - másik adat
*/
// Ez egy inline függvény, amit minden fordítási egységben
// definiálni kell.
inline int max(int a, int b) { return a > b ? a : b; }
#endif // FUGGVENYEIM
Fordítás parancssorból:
g++ nagyobb_main.cpp fuggvenyeim.cpp -o nagyobb_main
Fordítás IDE segítségével:
Fordítás parancssorból make segítségével:
Elő kell állítani a függésegeket leíró Makefile
-t pl:
Figyelem: a Makefile tabulátort kell tartalmazzon, szemben a C ill. C++-al!
le kell futtatni a make programot
make