C++ előadás és gyakorlat

Kitlei Róbert

2008/2009 tavaszi félév

Osztály

Osztály: a beépített adattípusokhoz hasonlóan kezelhető, felhasználói adattípus megvalósítása

Osztály

Adattag: az osztályhoz tartozó adatok felépítését leíró deklarációk (a függvények nem)

struct S {
int i;
double d;
};

Osztály

S s;
int i = s.i;
S* sp;
int i = (*sp).m;
int j = sp->m;

Osztály

struct A {
int i;
};

struct B {
A a;
A* ap;
};

B b;
int i = b.a.i;
B* bp;
int j = bp->ap->i;

Osztály

struct Link
{
Link* succ;
Link* prev;
int val;
};

Osztály

struct List;

struct Link
{
int elem;
Link* succ;
List* main_list;
};

struct List
{
Link* head;
};

Osztály

Statikus (osztályszintű) adattag: mindig pontosan egy példány van belőle, és ez magához az osztályhoz tartozik

struct S {
static int s;
int d;
};

Osztály

Date::x
d.x // ha d Date típusú
int Date::x;

Osztály

Tagfüggvény: az osztálydefiníción belüli függvénydeklaráció

Osztály

struct Date {
void f(); // csak deklaráció
int g() { return 4; }; // definíció
...
};

void Date::f() { ... }
// f definíciója

Osztály

struct szam {
string szoveg() {
return (poz ? "" : "-") + abszolut();
}

string abszolut() { ... };
...
};

Osztály

Statikus tagfüggvény

struct peldanyszamlalo {
peldanyszamlalo() { ++p; }
~peldanyszamlalo() { --p; }

static int peldanyszam() { return p; };

static int p;
...
};

Osztály

Konstans tagfüggvény

struct peldanyszamlalo {
peldanyszamlalo() { ++p; }
~peldanyszamlalo() { --p; }
int peldanyszam() const { return p; };
static int p;
...
};

Osztály

this mutató

struct s {
int a;

s(int a) {
this->a = a;
}
};

Osztály

Módosító függvények

Date d;
d.add_day(3).add_month(2).add_year(4);
((d.add_day(3)).add_month(2)).add_year(4);
Date& Date::add_year(int n) {
// módosító kódrészlet
return *this;
}

Osztály

Operátorok

Osztály

Operátorok

struct X {
X operator+(X);
double operator+(int);
};

X operator+(int, X);
X a, b;
X c = 2 + a + b + 1;

Osztály

struct X {
X operator++(); // egyoperandusú előtag, ++x
X operator++(int); // egyoperandusú utótag, x++
};

X operator++(X); // egyoperandusú előtag, ++x
X operator++(X, int); // egyoperandusú utótag, x++

Osztály

=, [], () és -> operátorok

Osztály

operator() operátor

Osztály

operator() operátor

struct X {
int operator()();
int operator()(int);
int operator()(char);
};

X a;
int i = a() + a(1) + a('a');

Osztály

Osztály

Osztály

Interfész: az osztály által a külvilág számára felkínált műveletek összessége

struct s {
public: // nyilvános szakasz kezdete
int nyilvanos();

private: // átlátszatlan szakasz kezdete
int rejtett;
};

Osztály

Invariáns: az objektum élettartama alatt végig fennálló, az objektumra vonatkozó tulajdonság

Osztály

struct és class kulcsszavak

Osztály

struct és class kulcsszavak

Osztály

Adattagok elrejtése (information hiding): egyetlen adattag sem nyilvános

Osztály

Értékadás

struct A {
int i;
double d;
};

A a = { 15, 642.9 };

Osztály

Konstruktor (constuctor): kezdetiérték-adó függvény

struct racionalis {
racionalis(int, int);

private:
int szamlalo;
int nevezo;
};

Osztály

Alapértelmezett konstruktor: paraméter nélküli konstruktor

Osztály

Date d = Date(1,2,3);
Date d(1,2,3);
// ugyanannak a konstruktornak kétféle hívása

Date d;
// alapértelmezett konstruktor hívása
// ha nincsen, fordítási idejű hiba

Osztály

Tag-kezdőérték lista (member initializer)

struct s {
Date(int a, int b, int c)
: aa(a), bb(b), cc(c, 123.0) { ... }
int aa;
int bb;
sajat_osztaly cc;
// van sajat_osztaly(int, double) konstruktora
}

Osztály

Másoló konstruktor (copy constructor)

Osztály

Másoló konstruktor

Osztály

Általános séma másoló konstruktorra és értékadás operátorra

struct T {
// másoló kostruktor
T(const T& t);
// értékadó operátor
T& operator=(const T& t);
// destruktor
~T();

private:
// segédfüggvények
T copy(const T& t);
void T::clear();
}

Osztály

void T::clear() {
// kitöltendő:
// felszabadítja az
// osztályban lefoglalt erőforrásokat
// (pl. memóriaterületeket)
}

T T::copy(const T& t) {
// kitöltendő:
// az objektum helyes másolásának egyedi kódja
}

Osztály

T::T(const T& t) {
copy(t);
}

T& T::operator=(const T& t) {
if (&t != this) { // önmagunkat nem módosítjuk
clear();
copy(t);
}
}

// a destruktor gyakran így néz ki
T::~T() {
clear();
}

Osztály

struct complex {
complex(int x = 0, int y = 0) {...}
};

complex z = 2;
// ekvivalens ezzel:
// complex z = complex(2, 0);

Osztály

struct Pont { Pont(int x, int y = 0) {...} };

void f(Pont) { ... }

f(2);
// ekvivalens ezzel:
// f(Pont(2, 0));

Osztály

Destruktor

struct s {
s() { mem = new int[10000]; }
~s() { delete[] mem; }

int* mem;
};

Osztály

Erőforrások robosztus kezelése

Eroforras e;
try {
e = lefoglal();
kezel(); // kivétel váltódik ki
// 1. lehetőség
} catch (...) {
// 2. lehetőség
}
// 3. lehetőség

Osztály

Eroforras e;
try {
e = lefoglal();
kezel(); // kivétel váltódik ki
// 1. lehetőség
} catch (...) {
// 2. lehetőség
}
// 3. lehetőség

Osztály

Osztály

Erőforrás ≡ Osztály

Osztály

Öröklődés, származtatás

Osztály

struct EPolg { ... };

struct Hallgato { EPolg e; ... };

Osztály

struct Hallgato : public EPolg { ... }

Osztály

Hallgato*  h;
EPolg* ep = h;

Osztály

struct EPolg { void kiir() const {...} };

struct Hallgato : public EPolg {
void kiir() const {
kiir(); // a Hallgato művelete
EPolg::kiir(); // az EPolg művelete
}
};

Osztály

struct EPolg {
EPolg(string n) : nev(n) { ... }
string nev;
};

struct Hallgato : public EPolg {
Hallgato(int e, string n)
: evfolyam(e), EPolg(n) { ... }
int evfolyam;
};

Osztály

struct EPolg {
EPolg(const EPolg&);
EPolg& operator=(const EPolg&);
};

struct Hallgato : public EPolg {
Hallgato(int e, string n)
: evfolyam(e), EPolg(n) { ... }
int evfolyam;
};

Hallgato h;
EPolg e = h; // csak az EPolg rész konstruálódik meg
e = h; // csak az EPolg rész másolódik le

Osztály

Osztályhierarchia

Osztály

Virtuális függvény (metódus)

Osztály

struct EPolg {
string nev;
virtual void orara_megy() const {
cout << nev << " polgar orara megy" << endl;
};
};

struct Hallgato : public EPolg {
void orara_megy() const {
cout << nev << " hallgato orara megy" << endl;
};
};

Hallgato h;
EPolg& e = h;
e.orara_megy();
// EPolg változóra hívtuk meg,
// de a Hallgato függvénye hajtódik végre

Osztály

Osztály

Tisztán virtuális függvény: nincsen definíciója az adott osztályban

Absztrakt osztály: tartalmaz tisztán virtuális függvényt

struct Alakzat {
virtual void rajzol() const = 0;
};

Osztály

Többszörös öröklődés: egy osztálynak több őse is lehet

struct A { virtual void f() { ... } };
struct B : public A { virtual void f() { ... } };
struct C : public A { virtual void f() { ... } };
struct D : public B, public C { virtual void f() { ... } };
struct E : public B, public C { };

D d; E e;
d.f(); // a D-beli f-et hívja
e.B::f(); // egyértelműsíteni kell
e.A::f(); // hiba: két A-t is öröklünk, nem egyértelmű

Osztály

Többszörös öröklődés

struct A { virtual void f() { ... } };
struct B : public A { virtual void f() { ... } };
struct C : public A { virtual void f() { ... } };
struct D : public B, public C { virtual void f() { ... } };
struct E : public B, public C { };
// E helytelen: felül kell bírálni benne f-et

D d;
e.B::f();
e.A::f(); // most már ez is egyértelmű

Osztály

Barát függvény: olyan osztályon kívüli függvény, amely hozzáférhet az osztály átlátszatlan részéhez is

struct S {
friend istream& operator>>(istream&, S&);
};

istream& operator>>(istream& is, S& s) { ... }

Osztály

Barát függvény

Osztály

Beágyazott osztály (embedded/nested class) vagy tagosztály (member class)

Osztály

Beágyazott osztály

struct S {
struct T {
T(int);
double f(double, string);
};
};

// a beágyazott osztály függvényeinek definíciói
S::T::T(int i) { ... }

double S::T::f(double d, string s) { ... }

Sablon

Generatív programozás: új kódrészlet programmal történő előállítása

Generikus programozás: algoritmusok és adatszerkezetek típusfüggetlen megvalósítása

Sablon

C++ generikus nyelvi eszköz: sablon (template)

Sablon

template <class T, int msize> class Buffer {
T v[];
const int max_size;
public:
Buffer() : max_size(msize) {}
...
};
template <class T, T t> class C { ... };

Sablon

template <class T>
struct fa {
void bejaras() const;
...
};

template <class T>
void fa<T>::bejaras() const { ... }

Sablon

Példányosítás (instantiation): konkrét osztály vagy függvény készítése a sablonból

Sablon

Példányosítás

Sablon

template <class T>
void f(T t) { cout << t.x; }

f<int>(1); // hiba: int-nek nincsen x adattagja

struct x { int x; };

f<x>(x()); // x-ben van x adattag

Sablon

vector<list<int>> v;    // helytelen
vector<list<int> > v; // helyes
template <int i> class sablon_osztaly { ... };

sablon_osztaly<256 >> 3> s;

Sablon

Függvénysablonok példányosítása

#include <algorithm>

int x = 4, y = 2;
double u = 1.2, v = 2.1;
swap(x,y); // swap(int, int)
swap(u,v); // swap(double, double)
swap<int>(x,y);

Sablon

template <class T> T max(T, T);

max<int>('a', 1);
max<double>(2.7, 6);
// minősítés nélkül mindkettő többértelmű lenne,
// mert konverzióra lenne szükség

Sablon

template<class T = int, int meret = 100>
struct verem { ... };

Stack<> s1;
Stack<int, 100> s2; // típusa azonos s1-gyel
Stack<double, 20> s3;
template<class T>
T sum(T* b, T* e, T init = T()) {
while (b != e) init += *b++;
return init;
}

Sablon

Specializáció (specialization): a típusparaméterek bizonyos kombinációja esetén az alapesettől eltérő definíció használata

Sablon

Specializáció

template<class A, class B, class C, class D>
struct S { ... };

template<>
struct S<int, int, int, int> { ... };

// parciális specializáció
template<class B, class C, class D>
struct S<int, B, C, D> { ... };

// parciális specializáció
template<class A, class B, class C, class D>
struct S<A*, B, C, D*> { ... };

Sablon

Sablonok hibaüzenetei

Sablon

Metaprogramozás: program készítése vagy átalakítása program segítségével

Sablon

Metaprogramozás

#include <iostream>

template <int N>
struct Factorial {
enum { value = N * Factorial<N-1>::value };
};

// specializáció: a rekurzív példányosítás vége
template <>
struct Factorial<1> { enum { value = 1 }; };

const int fact15 = Factorial<15>::value;

Polimorfizmus

Többalakúság vagy polimorfizmus (polymorphism): különböző adattípusok közös kezelése

Polimorfizmus

Univerzális polimorfizmus: egyetlen absztrakt megvalósítás tetszőleges (megfelelő tulajdonságú) típusra működik

Polimorfizmus

Ad hoc polimorfizmus: csak típusok véges halmazán működik

Polimorfizmus

Explicit típuskonverziók (cast)

Polimorfizmus

Explicit típuskonverziók (cast)

struct S : public P { ... };

P p;
S s = static_cast<S>(p);

int i = static_cast<int>(4.0);

Polimorfizmus

Explicit típuskonverziók (cast)

int* pi;
char* pc = reinterpret_cast<char*>(pi);

Polimorfizmus

Explicit típuskonverziók (cast)

const int i = 1;
const int* pi = &i;
int* p2i = const_cast<int*>(pi);
*p2i = 2;
// i értéke 2 lett

Polimorfizmus

"C stílusú" típuskonverzió

int i = (int)4.0;
int i = int(4.0);
// mindkét változat ekvivalens

Polimorfizmus

Explicit típuskonverziók (cast)

Polimorfizmus

// dynamic_cast példa

struct A {
void f() { cout << "A"; }
virtual void g() {}
};

struct B : public A {
void f() { cout << "B"; }
};

struct C : public A {
void f() { cout << "C"; }
};

Polimorfizmus

// dynamic_cast példa (folyt.)

void f(A* arg) {
B* bp = dynamic_cast<B*>(arg);
C* cp = dynamic_cast<C*>(arg);

bp ? bp->f() : cp ? cp->f() : arg->f();
}

int main() {
A a; B b; C c;
A *ap = &a, *bp = &b, *cp = &c;
f(ap); f(bp); f(cp);
}

Polimorfizmus

dynamic_cast példa kimenete: ABC