Előnyei
int f(double, char);
int g(double a, char b);
void
visszatérési típus: a függvény nem tér visszavoid e();
void
kulcsszó azt is jelezheti, ha nincsenek paraméterekint e2(void);
int f(int i, int j) {
return i + j;
}
return
utasítás
void
függvényekben alkalmasvoid csak_ha_i_nem_nulla(int i) {
if (0 == i) return;
...
}
return
utasítás
int f() {
if (egyszerű feltétel) return 1;
else {
// bonyolult számítás
}
}
return
visszatér a függvényből, a fenti kód így is megírhatóint f() {
if (egyszerű feltétel) return 1;
// bonyolult számítás: csökkent a behúzása
}
return
utasításint duplaz(int i) { return 2 * i; }
...
int i = duplaz(123);
int globalis;
int duplaz(int i) { ++globalis; return 2 * i; }
...
int i = duplaz(123) + globalis;
// i értéke nem definiált
double osszeg(double i, double j) { return i + j; }
// formális paraméterek: i, j
double d = osszeg(1., 2.) + osszeg(.3, .4);
// aktuális paraméterek
// i ⇐ 1.0, j ⇐ 2.0
// i ⇐ 0.3, j ⇐ 0.4
Paraméterátadás módja
const X*
: a függvény nem változtatja meg a mutatott objektumotParaméterátadás módja
T[]
automatikusan konvertálódik T*
típusraParaméterátadás módja
int f(int& n) { ++n; return n; }
int i = 734;
int& ir = i;
f(ir);
// i tartalma 735 lesz
// f visszatérési értékét nem használjuk fel
Paraméterátadás hivatkozás szerint
struct Nagy { int x[10000]; };
void mindet_novel(Nagy& n) {
for (int i = 0; i < 10000; ++i) ++n.x[i];
}
Paraméterátadás hivatkozás szerint
const X&
: ha a függvény nem változtatja meg az objektumot// az objektum kétszer is lemásolódik
Nagy nem_hatekony(Nagy n) { return n; }
// az objektum egyszer sem másolódik le
// csak a rámutató referencia
const Nagy& sokkal_hatekonyabb(const Nagy& n) {
return n;
}
Paraméterátadás során az adatáramlás iránya
int& melyiket(bool b, int& i, int& j) {
return b ? i : j;
}
...
int a, b;
int &ar = a, &br = b;
melyiket( true, ar, br) = 1; // a = 1;
melyiket(false, ar, br) = 2; // b = 2;
int* f();
// tegyük fel, hogy valahol meg is van valósítva
...
f()[4] = 1;
// a visszakapott tömb ötödik eleme
// felveszi az 1 értéket
int f(int a, int b = 7, double c = -33.3);
// helytelen
int f(int = 2, int, double = -33.3);
X*
és =
között szóközre van szükségint f(char*=0); // *=
int fib(int n) {
if (0 == n) return 1;
if (1 == n) return 1;
return fib(n-1) + fib(n-2);
}
int fib(int n)
{
if (0 == n) return 1;
if (1 == n) return 1;
return
fib(n-1) +
fib(n-2);
}
Nézzük végig a fib(3)
hívás menetét.
int fib(int n) // fib(3) hívás
{
if (0 == n) return 1; // nem ez az ág
if (1 == n) return 1; // nem ez az ág
return
fib(n-1) +
// újra meghívjuk: fib(2)
fib(n-2);
}
int fib(int n) // fib(2) hívás
{
if (0 == n) return 1; // nem ez az ág
if (1 == n) return 1; // nem ez az ág
return
fib(n-1) +
// újra meghívjuk: fib(1)
// fib(3) itt áll
fib(n-2);
}
int fib(int n) // fib(1) hívás
{
if (0 == n) return 1; // nem ez az ág
if (1 == n) return 1; // visszatér: 1
return
fib(n-1) +
// fib(2) és fib(3) itt áll
fib(n-2);
}
int fib(int n) // fib(2) hívás
{
if (0 == n) return 1;
if (1 == n) return 1;
return
fib(n-1) + // fib(3) itt áll
fib(n-2);
// fib(2) továbbmegy
// a kif. eddigi értéke: 1
// meghívja: f(0)
}
int fib(int n) // fib(0) hívás
{
if (0 == n) return 1; // visszatér: 1
if (1 == n) return 1;
return
fib(n-1) + // fib(3) itt áll
fib(n-2);
// fib(2) itt áll
// a kif. eddigi értéke: 1
}
int fib(int n) // fib(2) hívás
{
if (0 == n) return 1;
if (0 == n) return 1;
if (1 == n) return 1;
return
fib(n-1) + // fib(3) itt áll
fib(n-2);
// fib(2) visszatér: 1+1
}
int fib(int n) // fib(3) hívás
{
if (0 == n) return 1;
if (1 == n) return 1;
return
fib(n-1) +
fib(n-2);
// fib(3) továbbmegy
// a kif. eddigi értéke: 2
// meghívja: f(1)
}
int fib(int n) // fib(1) hívás
{
if (0 == n) return 1; // nem ez az ág
if (1 == n) return 1; // visszatér: 1
return
fib(n-1) +
fib(n-2);
// fib(3) itt áll
// a kif. eddigi értéke: 2
}
int fib(int n) // fib(3) hívás
{
if (0 == n) return 1;
if (1 == n) return 1;
return
fib(n-1) +
fib(n-2);
// fib(3) visszatér: 2+1
}
A fib(3)
hívási fája:
fib(3)
fib(2)
fib(1)
fib(0)
fib(1)
Lehetséges szignatúrái
int main();
int main(char** argv, int argc);
int main(char** argv, int argc, char** envp);
argv
: a parancssori paraméterek (C sztringek) tömbjeargc
: a parancssori paraméterek számaenvp
: a futtató környezettől átvett paraméterekinline
: javaslat a függvény kódjának beillesztésére a hívások helyein
inline
-nak jelölt az, akár nembool
, char
, short
→ int
float
→ double
int
↔ double
Derived*
→ Base*
Derived
a Base
osztály leszármazottjaint pow(double, double);
int pow(int, int);
pow(1, 2); // helyes: int, int
pow(3.0, 4.0); // helyes: int, int
pow(5, 6.0);
// 3. feloldási szabály: int ↔ double
// helytelen, mert egyaránt lehetne
// pow((double)5, 6.0);
// pow(5, (int)6.0);
void (*f)(int, string);
(*f)(3, "abc");
f(3, "abc");
// a nyelv definíciója ezt is megengedi
// ugyanúgy hívódik meg, mint a fenti
typedef void (*sajat_fvmut)(int, string);
névtér: logikailag összetartozó deklarációk csoportosítása
namespace N {
int n;
void f(int);
}
N::n
namespace N {
string s;
...
}
void N::f(int x) { ... }
using
direktíva: lokális szinoníma bevezetése a névtér elemeireusing N::n;
using namespace std;
#include
-oljuk a fejlécetnamespace Lib = Precise_Library_Name_v5r824;
// a "szokásos lefutás"
int i = f();
int j = g();
// ...
// f és g -1 értékkel jelzi,
// ha hiba történt bennük
int i, j;
if ((i = f()) == -1)
{ // f-beli hiba kezelése
} else if ((j = g()) == -1)
{ // g-beli hiba kezelése
} else
// ...
throw kivételpéldány;
// kivétel kiváltása (dobása)
try {
// a kivételkezelt kódrészlet
} catch (Kivételtípus1 e) {
// egyik kivételkezelő
} catch (Kivételtípus2 e) {
// másik kivételkezelő
}
try
blokk a szokásos lefutás kódját tartalmazzatry
blokkon belül kivétel váltódik ki, a végrehajtás az első (pontosan) illeszkedő catch
ágon folytatódikcatch
ág, a kivétel a függvényen kívülre terjed továbbthrow
(paraméter nélkül): az eredeti hiba továbbterjesztésestd::unexpected()
függvény hívódik megvoid f(int i) throw(int, SajatTipus);