- Az
iterátorokat váró függvényeivel tömbökön is lehet dolgozni. - Referenciája csak lokális és globális változónak lehet.
- Egy osztály konstans adattagja a konstruktor törzsében kaphat értéket.
- Minden iterátor dereferálható.
- Template függvény hívásakor mindig meg kell adnunk a template paramétereket.
Megoldás
- I
- H, létezik heap is
- H, inicializáló listán
- I
- H, ez a template paraméterek levezetése
- Kivételt csak abban a függvényben kaphatjuk el, ahol eldobtuk.
- Többszörös öröklésnél mindig szükség van virtuális öröklésre.
- A new operátor értékét mindig ellenőrizni kell, mert ha elfogy a memória, NULL pointert kapunk.
- Konstruktorból és destruktorból nincs sok értelme virtuális függvényt hívni.
- Az inicializáló listán mindig az ott szereplő sorrendben történik az inicializálás.
Megoldás
- H
- H
- H
- (pontatlan megfogalmazás, de) I
- H, a deklaráció sorrendjében
- Az egyparaméteres konstruktor használható automatikus típuskonverzióra.
- Az unáris predikátumot hívják komparátornak.
- Az implicit operator= meghívja az adattagok értékadó operátorát.
- Tartalmazott objektum destruktora mindig lefut, ha a tartalmazó destruktora lefut.
- A
++iit
és aziit++
kifejezés ugyanazt az operátort hívja.
Megoldás
- I
- H, a komparátor a bináris
- I
- I
- H
- Az alábbi kódrészlet biztosan hibás:
Almafa::Almafa(Almafa const & a1) { Almafa a2 = a1; }
- A nyíl operátor nem overload-olható.
- Az inicializáló lista a konstruktor törzse után fut le.
- Virtuális destruktorra akkor is szükség van, ha az adott osztálynak nincs virtuális függvénye.
- A leszármazott osztály destruktora minden esetben meghívja az ősosztály destruktorát.
Megoldás
- I, végtelen rekurzió
- H
- H, előtte
- H, de Prog2-n néha igaz
- I
- A new által allokált hely felszabadítható free-vel is.
- Absztrakt ősosztálynak kell, hogy legyen virtuális metódusa.
- Ha egy ősosztálynak van virtuális destruktora, minden leszármazottnak kell destruktort írjunk.
- A referencia csak paraméterátadásra használható.
- Az
std::vector<int>::iterator iit = l.begin();
sor után iit + 1
hatására az iit
iterátor ugrik a következő elemre.
Megoldás
- H, mindenképpen delete kell
- I, ráadásul tisztán virtuális
- H, megoldja a fordító
- H, van referencia változó is
- H, az a kifejezés új iterátort ad vissza
- A fordító által generált másoló konstruktor meghívja az adattagok másoló konstruktorát.
- A
begin()
és azend()
az iterátorok jellemző tagfüggvényei. - A leszármazottban felüldefiniált virtuális függvény minden esetben meghívja az ősosztály megfelelő virtuális függvényét.
std::list<int>::const_iterator
segítségével nem járható be a lista, mert az iterátor konstans, mindig ugyanarra az elemre mutat.- A virtuális függvény mindig lassabb, mint a nem virtuális.
Megoldás
- I
- H, a tárolóé
- H, előtte
- H, de Prog2-n néha igaz
- I
- A delete null pointer esetén kivételt dob.
std::vector<std::string>
nem létezhet, mert azstd::string
-ek dinamikusak, és memóriaszivárgás keletkezne.- Kivétel dobása előtt meg kell hívnunk a destruktorokat, különben memóriaszivárgás lesz a programban.
- Template osztály példányosításakor mindig meg kell adnunk a template paramétereket.
- Publikus öröklésnél a leszármazott osztály az ősosztály minden tagfüggvényét megörökli.
Megoldás
- H, szabvány szerint nem csinál semmit
- H
- H, automatikusan meghívódnak a destruktorok
- I, levezetés csak függvényeknél van
- I (kivéve a konstruktort)
- Az
operator+=
automatikusan keletkezik, ha vanoperator+
. - Az eleje-vége iterátorpár konvenció szerint balról nyitott, jobbról zárt intervallum.
- Bármelyik osztály példányosítható.
- Beugróban az STL vagy C++ puskából néhány igazhamis megoldása egy az egyben kiolvasható.
- Ha funktorokkal szeretnénk dolgozni, template kódot kell írnunk.
Megoldás
- H, ez két különböző operátor
- H, pont fordítva
- H, az absztrakt osztályok nem
- I, nyomtass!
- H,
operator()
nem csak template osztálynak lehet
- Az
std::find
visszatérési értéke egy iterátor. - Két azonos típusú iterátor között definiált az egyenlőség operátor.
- Publikus öröklésnél a leszármazott osztály az ősosztály minden konstruktorát megörökli.
- Vannak olyan iterátorok, amin n léptetés megoldható egyetlen lépéssel, de nem mindegyiken.
- Az
std::remove(it1, it2, érték)
nem törli ki a tárolóból az elemeket.
Megoldás
- I, iterátor a megtalált elemre, vagy az end
- I
- H
- I, it += n, de lista iterátorának nincs
- I, csak az elejére rakja a többit
template <typename T> /* 2 */
void print(T const & tarolo) { /* 1, 3 */
bool elso = true;
for (typename T::iterator iit = tarolo.begin(); /* 4, 5 */
iit != tarolo.end(); /* 5, 6 */
++iit) /* 7 */
{
if (!elso) /* 10 */
std::cout << ", "; /* 9 */
std::cout << *iit; /* 8 */
elso = false;
}
}
for (auto iit = tarolo.begin(); iit != tarolo.end(); ++iit)
std::cout << *iit; // ez is jó
for (auto const & elem : tarolo)
std::cout << elem; // ez is jó
- 2p a tároló van átvéve paraméterként, semmiképp sem iterátorok!
- 1p sablon függvény kell
- 1p
const&
szerint van átvéve, nem másoljuk le a kiírás kedvéért - 1p
T::iterator
a típusa az iterátornak (kell atypename
, de a pont jár anélkül is) - 1p a tároló
.begin()
és.end()
függvényének hívása - 1p a tároló végének vizsgálata
!=
operátorral (<
nem biztos, hogy jó) - 1p az iterátor léptetése
++
operátorral (mindegy, hogy pre- vagy post, ugyanakkor+= 1
ésiit = iit+1
nem biztos, hogy jó) - 1p
*
operátor használata az iterátoron - 1p a vessző kiírásának logikája
- ajándék 1p, ha az elején/végén nincs vessző
Írj függvényt, amely kiválasztott adatokat másol egyik helyről a másikra (copy_if
)! A bemenő tartomány iterátorokkal adott, a cél tartomány eleje szintén. Az elemek kiválasztását (melyik a másolandó elem, melyik nem) egy paraméterként átvett predikátummal kell megoldani – ha az igazat ad, az elem másolandó. Adjon vissza a függvény egy iterátort, amely azt mutatja, meddig írt a cél helyre adatokat!
Miért van szükség a visszatérési értékre? Mutass példát, amelyben egy 10 elemű, egész számok std::list
-ből másolod a páros számokat egy tömbbe!
template <typename INIT, typename OUTIT, typename PRED> /* 2, 3 */
OUTIT copy_if(INIT begin, INIT end, OUTIT to, PRED p) { /* 1, 8 */
for (INIT iit = begin; iit != end; ++iit) { /* 4 */
if (p(*iit)) { /* 5 */
*to = *iit; /* 6 */
++to; /* 7 */
}
}
return to; /* 8 */
}
bool paros(int i) { return i % 2 == 0; }
std::list<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; /* 9 */
int cel[10]; /* 10 */
// Innen tudja a hívó, hogy hány adatelem lett a cél helyen.
int *eddig = copy_if(v.begin(), v.end(), cel, paros); /* 11, 12 */
for (int *p = cel; p != eddig; ++p) /* 13 */
std::cout << *p << ", ";
- 2p a függvény paramétere 3 darab iterátor (ettől, eddig, ide)
- 1p template a függvény ÉS a két iterátor (ettől+eddig, ide) típusa különböző lehet (2 külön template paraméter kell, lásd a példát)
- 1p predikátum is template paraméter
- 1p a tartomány bejárása, fontos: balról zárt, jobbról nyílt;
*begin
beletartozik,*end
nem.iit < end
nem jó,iit += 1
sem. abegin
és azend
a paraméterek, függvényhívás itt nem lehet! - 1p az elem olvasása az iteratoron keresztül (
*iit
, kell a csillag) - 1p az elem cél helyre írása az output iteratoron keresztül (
*to =
...) - 1p output iterator lép és csak akkor lép, ha volt másolt adat
- 1p output iterator visszaadása, a visszatérés típusa helyes
- 1p példában a lista létrehozása (feltöltés lényegtelen)
- 1p példa cél tömbje, legalább 10 elemű (lehet hogy mind páros!)
- 1p függvény hívása, listán
begin()
ésend()
használata,paros()
itt nem hívódik meg - 1p visszatérési érték eltárolása,
int*
típusú a változó - 1p tömb bejárása pointerrel, vagy
i = 0; i < eddig-cel; ++i
-
1p lista létrehozása
-
1p beolvasás fájl végéig
(minden eof, null, 0, -1 és hasonló dolog esetén az egész feladat nulla pont)
-
1p listába fűzés
(ha nincs eltalálva a függvény neve, most jó az, csak a szándék érezhető legyen :D)
-
1p accumulate hívása, lista
begin
ésend
függvényeinek használata (ne maradjon le a()
) -
1p akkumulátor kezdeti értéke 0
- 1p halmaz típusa, template paraméter sztring
- 1p elemek beszúrása
- 1p bejáráshoz iterátor típusa:
tároló<miket>::iterator
, esetlegconst_iterator
- 1p
begin()
tagfüggvény hívása a tárolón, legyen kint a () - 1p
end()
tagfüggvény hívása a tárolón, legyen kint a () - 1p iterátorokon használt műveletek, !=, ++ és *
#include <iostream>
using namespace std;
class A {
private:
int k;
public:
A(const int i = 0) :k(i) { cout << 'k'; }
A(const A& a) { k = a.k; cout << 'c'; }
void operator=(A uj) { k = uj.k; cout << 'e'; }
A operator*(int i) { cout << i*100; return *this; }
~A() { cout << 'd'; }
};
A& operator*(int i, A& a) { cout << i; return a; }
int main() {
A a(1); cout << '\n';
A b = a; cout << '\n';
a = a * 2; cout << '\n';
a = 3 * a; cout << '\n';
}
#include <iostream>
using namespace std;
class A {
private:
int k;
public:
A(const int i = 0) :k(i) { cout << 'k'; }
A(const A& a) { k = a.k; cout << 'c'; }
void operator=(A uj) { k = uj.k; cout << 'e'; }
A operator*(int i) { cout << i*100; return *this; }
~A() { cout << 'd'; }
};
A& operator*(int i, A& a) { cout << i; return a; }
int main() {
A a(1); cout << '\n'; // k
A b = a; cout << '\n'; // c
a = a * 2; cout << '\n'; // 200ced
a = 3 * a; cout << '\n'; // 3ced
// dd
}
A rajz összes osztálya rendelkezésére áll. Az std::vector
sablon felhasználásával hozz létre egy olyan objektumot (tar
),
ami "tárolni" tud AA
és AB
típusú objektumpéldányokat is. Ezután a dinamikus memóriában hozz létre 100 db AB
példányt
és egy AA
példányt úgy, hogy később elérd azokat! Ügyelj a konstruktorok paraméterezésére!