wiki.git.bme.hu/index.php/Programtervez%C3%A9s_I
1. Mi a fejállományok szerepe C és C++ nyelvben és hogyan használjuk őket?
http://en.wikipedia.org/wiki/Header_file
A fejállományok különálló, újrahasznosítható programkódokat tartalmazó szöveges fájlok, melyeket az előfordító az #include utasítás hatására másol be a forráskódunk elejére, ahol pl az #include <iostream> utasítást kiadtuk. Hasznosak, mert így egy programrészletet több programunkban is használhatunk úgy, hogy ha módosításra szorul, akkor csak egy helyen kell módosítani rajta. Szokás, hogy a .h fájlokban csak a függvények szignatúráit, osztályok, változók deklarációját sorolják fel (pl. void fg(int n1, char c1);), majd a kifejtéseket a fejállományba #include-olt fájlokban (.h, .hpp, .cpp) fejtik ki.
Itt még érdemes megemliteni, hogy az #include ”file” esetén először a forrásfájl mappájában keresi a fordító a file nevű állományt, #include <file> esetén meg a fordító könyvtárában keres.
Régen, amikor még nem szabványosították rendesen a C++-t, használták az alap (K&R) C-ben megírt fejállományokat, amelyeknek .h volt a kiterjesztése (pl math.h). A szabványosítás során azonban bevezették a névtereket, és az összes függvényt betették az std névtérbe. Ezzel, az volt a gond, hogy eddig nem használtak a programozók using namespace std-t vagy std::cout-ot, ezért meghagyták nekik az eredeti helyükön az iostream.h-t meg a többit, és az std-be ezeket a .h végződés nélkül másolták be. Miért van cmath és math.h? http://www.parashift.com/c++-faq-lite/std-headers.html A standard C-ben is szereplő fejállományokat (18 ilyen van) úgy tették be a standard névtérbe, hogy a .h-t elhagyták, de egy c előtagot tettek: math.h -> cmath. Ez annyit jelent, hogy ezek C-ben vannak írva, és ugyanaz van a cstdio-ban, mint az stdio.h-ban. A többi, nem C-szabvány fejállomány (pl iostream, string) .h-s verziója nem támogatott, de még használható, .h nélküli verziója pedig támogatott, és az std névtérben van.
2. Milyen alapvető változókat használhatunk a C és C++ nyelvben?
http://hu.wikipedia.org/wiki/C%2B%2B#T.C3.ADpusok.2C_v.C3.A1ltoz.C3.B3k.2C_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).
Adattípus |
Értékkészlet |
Méret(byte) |
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 |
10 |
19 |
A memóriában létrehozott tárolókat névvel látjuk el, amely 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 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!
3. Ismertesse a névtér fogalmát!
A fordító a programban használt neveket különböző névtereken (namespace) tárolja. Egy névtérben lévő neveknek egyedieknek kell lenniük, azonban a különböző névtereken azonos néven is szerepelhetnek, azaz a névterek a láthatósági szabályokat teszik könnyebben alkalmazhatóvá. Egy névtérben logikailag összefüggő változókat, függvényeket, típusokat tárolunk. Egy osztály/struktúra egyben a nevével azonos nevű névteret is definiál.
// Az Állat névtéren belül szerepel a Farkas és Medve osztályok definíciója
namespace Allat{
class Farkas{...};
class Medve{...};
}
Egy névtér elemeire háromféleképpen hivatkozhatunk:
· Globális névfeloldással (using direktíva), ekkor a névtér összes eleme használható, használata körültekintést igényel, mivel egész névterek importálásakor könnyen névütközés lehet:
# include <iostream>
using namespace std; //A standard (std) névtér globális használata
int main(int argc, char *argv[])
{
cout << "Globális névfeloldás" << endl; //std::cout << "Globális névfeloldás" << std::endl; helyett
return 0;
}
· Explicit névfeloldással megadva a kívánt névteret, közvetlenül a feloldani kívánt elem esetében:
# include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Explicit névfeloldás" << std::endl;
return 0;
}
· A kívánt elem nevének feloldásával (using deklaráció):
# include <iostream>
using std::cout; //A standard (std) névtérbeli cout globális használata
int main(int argc, char *argv[])
{
cout << "Csak a cout lett feloldva" << std::endl;
return 0;
}
Létezik az úgynevezett névtelen névtér, amit arra használhatunk, hogy ne szemeteljük tele a globális névteret, megvédjük magunkat a többértelműségektől.
namespace
{
//amit el akarunk keríteni
}
ezt találtam (nem biztos, hogy jó, de ha jó, akkor legalábbis számomra érthetőbb)
Namespace -ek segítségével rendszereket hozhatunk létre a kódok rendezéséhez. Erre a legjobb mód egy hierarchikus rendszer felépítése. A legáltalánosabb neveket a hierarchia tetejére helyezzük, és az alsóbb szintekre kerülnek az egyre specifikusabb nevek.
A típusdeklarációk lehetnek: osztályok, interface -ek, struktúrák (struct), iterációs típusok (enum), delegate.
4. Mit értünk a "változó hatóköre" fogalom alatt?
A változó hatóköre alatt azt a programrészt értjük, amelyre nézve lokális az adott változó, vagy ha globális, akkor az egész kódot. A változó csak saját hatókörén belül létezik illetve lehet rá hivatkozni. Azonos nevű változók esetén a belső blokkban deklarált változóra történik a hivatkozás, ezen változtathatunk a hatókör-feloldó operátorral (::). példa msdn-ről:
// expre_ScopeResolutionOperator.cpp
// compile with: /EHsc
// Demonstrate scope resolution operator
#include <iostream>
using namespace std;
int amount = 123; // A global variable
int main() {
int amount = 456; // A local variable
cout << ::amount << endl // Print the global variable, 123
<< amount << endl; // Print the local variable, 456
}
5. Hogyan konvertálja a C nyelv a típusokat az értékadó utasításokban?
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)
Temporális é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ípus"-nak megfelelően). Ha a konverzió nem elvégezhető, 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ípus" é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" azonos típusúak kell legyenek, kivéve a fent említett típusmódosítókat.
6. Milyen operátortípusokat ismer és mit ért az operátorok precedenciáján?
1. Számtani operátorok
+, -, *, =, %, /, --, ++
2. Összehasonlító/ relációs operátorok
==, <, >, !=, <=, >=
3. Logikai operátorok
!, ||, &&
4. “Bit”-es operátorok
^, &, |, <<, >>, ~
5. Összetett operátorok
+=, -=, *=, /=, %=, ^=, <<=, >>=, &=, |=
6. Tag- és mutatóoperátorok
*, [ ], ->, “.” ,
7. Egyéb
sizeof, new
Az operátorok precedenciája a műveletek elvégzési sorrendjét jelenti. A sorban feljebb álló műveletet végzi el először a program.
(Szerintem itt az unáris(egyoperandusú, pl ++), bináris(kétop.. pl +), és trináris ( ? : ) operátorokra gondoltak - A.Dani)
7. Ismertesse a mutató típusú változók használatát!
int a=5; (0x8130- ezen a címen van)
int*cucc=0; (0x8134- ez meg ezen)
Address |
Contents |
&a=0x8130 |
a=0x00000005 |
cucc=0x8134 |
*cucc=0x00000000 |
cucc=&a;
Address |
Contents |
0x8130 |
0x00000005 |
0x8134 |
0x00008130 |
*cucc = 8;
Address |
Contents |
0x8130 |
0x00000008 |
0x8134 |
0x00008130 |
8. Ismertesse a referencia típusú változók használatát a natív kódú programokban!
int i; // i egy egyszerű, egész típusú változó. int &ir=i; // ir egy egész referencia. Egy referenciának muszáj kezdőértéket adni // (kivéve, ha //függvénydeklaráció paraméterlistájában szerepel – ekkor a // híváskor inicializálódik). |
A referencia olyan, mint mikor egy objektumnak még egy nevet adnánk (alias). Az itteni sor tehát azt eredményezi, hogy arra a tárterületre, amire eddig az i névvel hivatkoztunk, most már az ir névvel is hivatkozhatunk. A referenciák használata megegyezik a sima változók használatával. Amikor függvénynek referenciát adunk át, azzal nem készül róla másolat, lokális változó a függvényben, hanem a függvény által végzett módosítások az eredeti változón hajtódnak végre:
Alles in allem: A hivatkozást egy másik objektum, a célobjektum nevével lehet inicializálni. Ettől a pillanattól kezdve a hivatkozás úgy viselkedik, mintha maga a célobjektum lenne; bármi ,amit a hivatkozással teszünk, megtörténik a célobjektummal is.
(A hivatkozás nem lehet nullértékű, így ha van esély arra, hogy a futás közben a célobjektumunk kinullázódik, akkor nem használhatunk referenciát (hivatkozást) ). Ilyen esetekben pointer célszerűbb.
fv(int& param)
{
param++;
}
int main()
{
int a=0;
printf(“%i”,a); // 1
return 0;
}
9. Magyarázza el a dinamikus változók használatának előnyeit a C és C++ nyelvekben!
A lokális változók a függvényparaméterekkel együtt a
veremterületen vannak, a dinamikusan tárolt változók pedig a heap-en.
A dinamikus változót programfutás közben is lehet törölni, így memóriát
szabadíthatunk föl a fölösleges változók törlésével. A dinamikus változókból
alkotott tömböknek futásidőben is meghatározhatjuk a méretét.
A veremterületen tárolt változók automatikusan törlődnek, mikor a függvény
visszatér a hívóhoz. Dinamikus memórián lefoglalt változó egészen addig
hozzáférhető marad, amíg célzottan fel nem szabadítjuk.
C-ben memóriafoglalás: malloc(),
felszabadítás: free()
C++ -ban memóriafoglalás new felszabadítás: delete kulcsszavakkal.
A globális változókhoz képesti nagy előnye, hogy csak azok a függvények érik el
az adatokat, amelyek ismerik a hozzájuk vezető pointert.
Itt még meg lehet említeni a memóriaszivárgást. Ez akkor van, ha nem töröljük a
lefoglalt memóriaterületet, vagy a pointerünknek más értéket adunk, mielőtt
töröltük volna, és így más memóriacímet oszt ki anélkül, hogy törölte volna az
előzőt.
10.Magyarázza el a natív tömbök memóriamodelljét!
(csaktipp, amit írok az helyes, viszont nemtom mire gondolnak
- A.Dani) A tömbök a memóriában folytonos memóriaterületen, az egyes elemek
egymás utáni memóriacellákban helyezkednek el. A tömb 0. elemére pointer mutat
(statikus tömbnél is, bár itt semmi nem utal rá), a tömb n. elemét a pointer
n-nel való növelésével kapott pointerrel érjük el:
(Ezt a gép úgy értelmezi, hogy n-t megszorozza annak a típusnak a
memórianagyságával, aminek a tömböt foglaltuk.)
int* a = new int(10);
a+=10;
printf(“%i”, *a); //567
11.Mit értünk pointer aritmetikán?
Pointerekkel különbözõ aritmetikai mûveleteket végezhetünk, ezek a következõ formájúak lehetnek:
Művelet |
Kifejezés |
Eredmény |
két, azonos típusú mutató kivonható egymásból |
p-q |
egész |
a mutatóhoz egész szám hozzáadása |
p+n ; p++ ; ++p ; p+=n |
mutató |
a mutatóból egész szám kivonása |
p-n ; p-- ; --p ; p-=n |
mutató |
két pointer összehasonlítása |
p==q ; p>q ; stb. |
bool (true/false) |
Ahol a q és a p (nem void* típusú) mutatók, az n pedig egész (int vagy long).
Minden mutatóval végzett mûvelet esetén képzeljük el azt, hogy a memória csak olyan típusú adatokból áll, mint amilyet az adott mutató megcímez, és ezek egyesével vannak megszámozva. Tehát például a ptr azonosítójú pointerrel való mûveletvégzés esetén azt tételezzük fel, hogy a memória legkisebb megcímezhetõ egysége a rövid egészt tartalmazó szó. Ha most a mutatóhoz hozzáadunk, vagy belõle levonunk egy egész számot, akkor az a megadott számú adattal való elõre-, vagy hátralépést fogja jelenteni, azaz például a ptr+5 értéke az a cím lesz, ahol az aktuálisan mutatott short utáni 5-dik rövid egész szó elhelyezkedik; a -ptr pedig a megelõzõ short-ra állítja ptr-t. Más szóval, ha egy mutatott adat képzeletbeli sorszáma i, akkor a mutatóhoz való n egész érték hozzáadása után az eredményül kapott mutató az i+n sorszámú adatot fogja megcímezni. A fentieket legkönnyebb egydimenziós tömbök segítségével szemléltetni. Tekintsük az alábbi definíciókat:
float vekt[20], *pv = &vekt[4];
A pv azonosítójú mutatót egy adott adat címével inicializáltuk. Ez alkalmazható statikus helyfoglalású változókra is, mert csak azt kötöttük ki, hogy ezek inicializátorai nem függhetnek más változók értékétõl, de itt nem az érték, hanem az elfoglalt cím lett felhasználva. A fenti definíciók után a pv, pv + 3, pv - 2,pv + 20 kifejezések sorban a vekt tömb 5-ödik, 8-adik, 3-adik és - nem létezõ - 25-ödik elemének címét adják meg (az utolsó tehát szintaktikailag helyes ugyan, de szemantikailag hibás).
A pointer - pointer alakú kifejezésnek csak akkor van értelme, ha a két mutató által megcímzett típus azonos; ekkor az eredmény a két adat távolsága adat-méretnyi egységben, vagyis itt is alkalmazzuk a fenti feltételezést a memóriáról, és az eredményt a két mutató által kijelölt két adat sorszámainak különbségeként kapjuk.
12. Hasonlítsa össze a C és a C++ stringek használatát!
http://cs.stmarys.ca/~porter/csc/ref/c_cpp_strings.html
http://www.prismnet.com/~mcmahon/Notes/strings.html
C-ben a string egy karaktertömb. Lényeges mindig figyelni rá, hogy a karaktertömbön belül, ha egy 5 karakteres[3] szöveget tárolunk akkor a 6. elem a NULL (\0) karakter legyen ( str[5]=NULL; mivel 0-tól kezdődik az indexelés). Ezt a null karaktert deklarációnál nem teszi be autómatikusan. A C-ben az #include <cstring> (vagy string.h, vagy az #include <iostream>-ben is benne van sok más dologgal együtt) segítségével tudjuk a stringkezelő függvényeket inkludálni.
C++-ban a string egy osztály amit az #include <string>-el tudunk includálni, vagy az standard névtérben is benne van (using namespace std;). Ez azt jelenti, hogy deklarációnál alapból egy üres, végén NULL karakterű stringet kapunk (magyarul kevésbé kell figyelni a nullkarakterre c++-nál). Itt is vannak stringkezelő függvények, amik a string osztályban vannak definiálva.
Minden C-ben használt stringkezelő fv-nek megvan a megfelelője a c++-os string osztályban, csak másképp kell meghívni (pl.: c-ben: strchr(miben,mit) (miben keresi a mit), c++-ban ez: miben.find(mi) ami ugyan azt csinálja). Emellet a c++ kicsit több stringkezelő fv-t állít rendelkezésünkre.
(Az első linkben van példa, hogy c-ben meg c++-ban mi hogy néz ki, mit szabad az egyikben és mit a másikban.)
13.Mi a függvény prototípusa, deklarációja, hogyan aktiváljuk a függvényeket?
prototípus: amikor csak leírjuk, hogy mik lesznek a bemenetek és a kimenetek pl:
int osszeado(int a, int b); //kell a ; (a függvény deklarációját szokás prototípusnak nevezni)
deklaráció: amikor kifejtjük, hogy pontosan mit is csinál a függvény. Néha csak ez van és elmarad a protoípus pl:
int osszeado(int a, int b)
{
return a+b;
}
Aktiválás alatt gondolom azt értjük, hogy meghívjuk kódból a függvényt, pl így:
int egy=1;
int ketto=2;
int harom=osszeado(egy, ketto);
cout << egy << “+” << ketto << “=” << harom << endl;
14.Mi az érték szerinti, a pointer és a referencia paraméterek használatának módja és értelme?
Érték szerinti paraméterátadás:
int fuggv(int ertek)
{
ertek++;
return ertek*2; // (vájtfülűeknek: itt “ertek” formális paraméter)
}
int main()
{
int a=2;
printf(“%i”,fuggv(a)); //6 (vájtfülűeknek: itt “a” aktuális paraméter)
printf(“%i”,a); //2
}
Az érték szerinti paraméterátadás során az átadott változóról (aktuális paraméter) másolat (formális paraméter) készül, amivel a függvény dolgozik, ebből következően az átadott paraméteren (“a”) nem tud a függvény változtatni, kizárólag a másolaton (“ertek”). Ez a változó lokális a függvényre nézve, tehát pl ertek nem létezik a main()-ben (mint ahogy “a” sem fuggv(int)-ben). Mivel másolat készül az átadott objektumról, ha mondjuk egy nagyobb méretű osztályt akarunk átadni a függvénynek, a másolás sok memóriát és processzoridőt igényelhet, ilyenkor hasznosabb az alábbi két módszer:
Cím szerinti átadás pointerrel:
void fuggv(int *ertek)
{
*ertek+=2;
}
int main()
{
printf(“%i”,fuggv(&a)); //4[4]
printf(“%i”,a); //4
}
Ez a paraméterátadás abban különbözik az előzőtől, hogy megmondtuk a függvénynek a változó memóriacímét, így hozzáfér közvetlenül a memóriacímen tárolt változóhoz. (Tulajdonképp a pointert adtuk át érték szerint)
Cím szerinti átadás referenciával:
void fuggv(int &ertek)
{
ertek+=2;
}
int main()
{
int a=2;
printf(“%i”,fuggv(a)); //4
printf(“%i”,a); //4
}
Ez annyiban más, hogy mint egy referenciát kérjük be a paramétert, és ugyanúgy tudunk rajta változtatni, kényelem szempontjából más csak, mint a pointeres átadás, mert ugyanúgy van a szintaxisa mint az érték szerinti, csak a függvény deklarációjában int *helyett int&-et kell írni. Valamint amikor átadjuk a változót a függvénynek, akkor a pointeresnél vagy pointer típusút kell átadni, vagy & jellel le kell kérni a memóriacímét, míg itt megadhatjuk paraméternek simán a normál int-et.
15.Mire szolgál a függvénypointer?
int (*fp)(float x); //int típusú fügvényre mutató pointer float paraméterrel
(Tulajdonképpen ugyanazt csinálja, mint a sima pointer, csak függvénnyel)
16. Ismertesse a szabványos C és C++ file kezelés lépéseit!
Jobb oldalra írom, hogy van C-ben (balodali a c++)
#include <iostream>
#include <fstream> //be kell includeolni a filázosához
using namespace std;
ifstream fin; //létre kell hozni a változót FILE * fin;
ofstream fout; FILE * fout;
int main ()
{
int i;
fin.open("be.txt"); //meg kell nyitni a fájlt fin=fopen(“be.txt”,”r”); //olvasásra nyitom meg
fout.open("ki.txt"); fout=fopen(“ki.txt”,”w”); //írásra nyitom meg
/* beolvasunk egy egész értéket i-be */
fin >> i; //olvasunk fscanf(fin,”%i”,&i);
/* kiirjuk i értéket egy file-ba */
fout << i << endl; //írunk fprintf(fout”%i\n”,i);
fin.close(); //végén bezárjuk a fájlt fclose(fin);
fout.close(); fclose(fout);
}
17.Mit nevezünk szöveges állománynak?
Hát ami nem bináris, vagyis ha elkezdünk belőle adatokat olvasni, akkor értelmes szöveget kapunk, nem pedig összevisszaságot.
Esetleg hogy valamilyen karakterkódolással tárolt szöveg van benne?
Szerintem: C-ben: karaktertömböt jelent (esetleg el lehet mondani a 2. feladatban a char-ról leírtakat) C++-ban: egy osztály (string osztály)
18.Magyarázza el az osztály és a példány fogalmát!
A megegyező szerkezetű, hasonló viselkedésű elemek mintája – Osztály (class)
Ez egy felhasználó által definiált típus. Az osztályhoz tartozó példány (instance) az objektum
megkülönböztethetők
„ismerik” saját osztályukat
UML (Unified Modelling Language)
//
http://digitus.itk.ppke.hu/~lovei/java/10/java10-02.html
Objektum: adatok összekapcsolása a hozzájuk tartozó műveletekkel.
Osztály: hasonló tulajdonságokkal és műveletekkel rendelkező objektumok összefogása
Példány: osztály egy példánya egy osztálybeli objektum[5]
pl.: objektumok: kacsa, bálna, víziló
osztály: állat (ebbe beletartoznak a kacsa, bálna, víziló objektumok, mert ugyanazok a tulajdonságaik érdekesek a számunkra (lábak száma, színe, stb) és ugyanazokat a műveleteket szoktuk rajtuk elvégezni (átlagéletkorszámítás, stb.)
ekkor az állat osztály egy példánya a bálna objektum
19.Mi a struktúra és az osztály közötti különbség
A struktúra alapértelmezésben public, a class private.
Struktúra nem tud öröklődni, és nem lehet konstruktora, destruktora, valamint nem kap alapértelmezett egyenlőség-operátort.
Struktúrát általában C-ben használunk, mert ott nincs class. C++-ban inkább class-t használunk mert többet tud
Struktúrában csak adatokat tudunk tárolni, nem tudunk hozzájuk tartozó függvényeket írni a struktúrán belül.
20.Mit nevezünk az adatrejtés elvének?
Az adatokat és az adatokat kezelő függvényeket egységként kezeljük méghozzá úgy, hogy a külvilág számára közömbös adatokat - kód részeket elzárjuk. Így megvalósul az adatrejtés elve.
Az adatokhoz közvetlenül nem engedünk hozzáférést (private vagy protected típusúak), és amit mégis el akarunk érni a kódból, azt osztálybeli függvény segítségével tesszük.
21. Hogyan szabályozhatjuk az osztálytagok kívülről való elérését?
● public - publikus - elérhető ezen objektumból s utódaiból is (és kívülről)
● private - privát - kívülről soha nem érhető el, s az utód objektumból se. Ha mégis elérhetővé kéne tenni, akkor írunk rá az osztályban egy public függvényt, ami visszaadja.
● protected - védett - hasonló a priváthoz, de az utód objektumból elérhető
● struct:alapértelmezés: minden mező és függvény publikus
● class:alapértelmezés: minden mező és függvény privát
22.Mit nevezünk adattagnak, és hogyan definiálhatjuk?
#include <iostream>
using namespace std;
class Szam
{
int szamom; //ez private << EZ AZ ADATTAG
public:
void kiir(){cout <<szamom<<endl; return 0;} << EZ A TAGFÜGGVÉNY
};
int main(int argc, char* argv[])
{
Szam elso(5);
elso.kiir(); //5
return 0;
}
23.Mit nevezünk tagfüggvénynek, és hogyan definiálhatjuk?
ld. előző
prototípus: amikor csak leírjuk, hogy mik lesznek a bemenetek és a kimenetek pl:
int osszeado(int a, int b); //kell a ;
deklaráció: amikor kifejtjük, hogy pontosan mit is csinál a függvény. Néha csak ez van és elmarad a protoípus pl:
int osszeado(int a, int b)
{
return a+b;
}
Aktiválás alatt gondolom azt értjük, hogy meghívjuk kódból a függvényt, pl így:
int egy=1;
int ketto=2;
int harom=osszeado(egy, ketto);
cout << egy << “+” << “ketto” << “=” << harom << endl;
24.Magyarázza el a this paramétert!
A this kulcsszó mindig az adott példányra mutató pointerrel egyenértékű (azért this. és nem that. hűha). this->val ekkor az adott példány val nevű adattagját fogja jelenteni.
(ez akkor érdekes ha egy változónevet többször is használunk (túlterheljük) akkor hogy tudja a program h az épp aktuális példányban használt ugyanilyen nevű változóra vagyunk kíváncsiak elé tesszük, hogy: this->)
25.Mit nevezünk konstruktornak, mi a feladata?
A konstruktor egy függvény ami az objektum példányosításakor fut le. A feladata az adattagok inicializálása, azok számára szükséges memória allokálása (new [vagy malloc]), esetleg az alapértelmezett változóértékek beállítása, ilyenek.
https://inf.nyme.hu/~soossandor/oktatas/cpp_01/cpp02ea.pdf 7. diától -> ez jó a 26., 27. és 28. kérdéshez
26.Milyen alapértelmezett konstruktorokat ismer?
A konstruktorok általában rendelkezhetnek paraméterekkel, amik az objektum kezdeti állapotát határozzák meg. A programnyelvek rendszerint megengedik, hogy azonos néven több, eltérő paraméterlistájú változat is szereplejen. Ilyenkor az objektum létrehozásakor használt argumentumok döntenek arról, melyik metódus fut le ezek közül. Néhány változatot külön névvel szokás illetni. Ilyenek a paraméter nélküli "alapértelmezett" (default), vagy az egyező osztályú "másoló" (copy) konstruktor.
Másoló konstruktorra példa:
Ha érték szerint adunk vagy kapunk objektumot egy függvénytől, ideiglenes
másolat készül róla. Ha egy felhasználó által definiált objektumról van szó,
akkor az osztályhoz tartozó másoló konstruktor hívódik meg.
Két típus: - shallow copy : Objektum tagváltozóinak pontos
másolatát viszi át egy másik
objektumba, ami
azt fogja eredményezni, hogy a mutatók ugyanarra a me
móriacímre fognak mutatni mindkét
objektum esetén. Ami azért nem túl
jó, mert meg fog hívódni egy
destruktor is, ami megkísérli a lefoglalt
memória felszabadítását, ahova (a
másolatban) a tagváltozó címére
mutató pointer mutat.)
- deep copy: Ebben az esetben a dinamikus
memóriaterületen lévő értékeket is meg-
duplázza.
27.Mit nevezünk destruktornak, mi a feladata?
A destruktor a példány törlődésekor lefutó függvény, feladata a dinamikusan foglalt memória felszabadítása. A konstuktorral szemben amiből több is lehet eltérő paraméterezéssel, ebből csak egy lehet értelem szerűen.
~osztálynév(){..} módszerrel hozzuk létre
A destruktornak nincs bemenő paramétere és visszatérési értéke sem !
28.Mutassa be a konstruktorhívás formáit!
statikus
dinamikus
Valaki pls csinálja meg a kifejtést.
class Valami{
public:
int x;
Valami::Valami()
{ x = 0; } // 1. konstruktor deklarációja
Valami::Valami( int ax )
{ x = ax; } // 2. konstruktor dekl. Az eltérő paraméterezés miatt lehet mindkettő
Valami::Valami(int ax, bool ketszer)
{
if(ketszer) x=2*ax;
else x=ax/2;
}
};
int main(int argc, char* argv[])
{
Valami elso; //0 lesz az értéke. Ide nem elso() kéne? -> ez így jó, nem kell a “()”
Valami mas(10); //10 lesz az értéke
Valami harmadik(8,true);
Valami negy(4,false);
cout << elso.x << endl; //kiír 0-t
cout << mas.x << endl; //kiír 10-et
cout << harmadik.x << endl; //kiír 16-ot
cout << negy.x << endl; //kiír 4-et
29. Hogyan szűnik meg, illetve szüntethető meg egy objektum, natív kód esetén?
delete elso; //az előző példánál maradva (felszabadítja az elso által foglalt memóriaterületet)
EKkor meghívódik a destruktor, ami van alapból (default), de csinálhatunk mi is a
~Valami(){ .. } módon a konstruktorhoz hasonlóan, de ebből csak egy lehet!!!
30. Hogyan lehet a konstruktorokat paraméterezni?
lásd 28., gondolom
ami a 28. feladatban van. Akkor paraméterezett egy konstruktor ha a zárójelben van megadva adat, ez az adat a paraméter (több is lehet, ez a 28. feladatban amit az “mas”, “harmadik” és “negy”-gyel csinálunk)
31. Hogyan lehet adattagoknak kezdőértéket adni a konstruktorokban?
nem biztos, de talán ennyi:
Valami::Valami(int ax=10, bool ketszer=true)
{
if(ketszer) x=2*ax;
else x=ax/2;
}
szerintem inkább így:
class nev{
tip at1;
… … … …
public:
tip at2;
… … … …
Konstruktor(tip p1, tip p2…): at1(p1), at2(p2) {}
} ;
32. Hogyan jellemezhetők a statikus adattagok és tagfüggvények?
én úgy emlékszem, hogy csak annyi, hogy ezek nem jönnek létre minden példánynál, hanem csak egyszer vannak a memóriában és akármelyik példány adataként hívjuk meg vagy módosítjuk, ugyanaz az egy adat módosul, pl
a.statikus=10;
b.statikus=5;
cout << a.statikus; //5-t fog kiírni
//feltételezve, hogy a és b ugyanannak az osztálynak a tagjai, aminek van egy statikus nevű int típusú static adattagja
A static kulcsszóval kell deklarálni.
Elérés
osztálynév::tag
Nem lehet az osztályban definiálni, hanem file (névtér) szinten
típusosztálynév::tag=érték
(A normál adattagok objektumonként, a statikus adattagok osztályonként léteznek. A Statikus adattagokat az osztály minden példánya elérheti. Erre volt példa a complex számos feladatnál.
A globális adattagoktól annyiban tér el, hogy nem érhetők el a program bármely részén. )
33.Mit nevezünk a friend függvénynek?
Ha egy osztály, vagy egy globális függvény számára elérhetővé szeretnénk tenni a privát, illetve a védett tagokat, akkor a friend kulcsszót használhatjuk a feladatra. A megoldáshoz a barátként használni kívánt osztályt, vagy függvényt friend-ként kell definiáljuk az osztályon belül.
class ellenseg1{
int hadititok;
}
class ellenseg2{
int valami;
int ellenseg2::spy(ellenseg1 ellen)
{
return ellen.hadititok;
}
}
int main()
{
ellenseg1 usa;
usa.hadititok=12345;
ellenseg2 germany;
cout << germany.spy(usa); //próbál kémkedni, de mivel az usa hadititok változója private így nem fér hozzá csak az ellenseg1 osztály beli függvény
}
De ha beépül a kém, akkor ennyiben változik a dolog:
class ellenseg1{
int hadititok;
friend ellenseg2::spy(ellenseg1 ellen);
}
class ellenseg2{
int valami;
int ellenseg2::spy(ellenseg1 ellen)
{
return ellen.hadititok;
}
}
int main()
{
ellenseg1 usa;
usa.hadititok=12345;
ellenseg2 germany;
cout << germany.spy(usa); //mostmár sikerrel tud kémkedni hiszen az ellenseg2 osztály spy függvénye “barátja” az ellenseg1-nek így látja az ő private változóit is
}
A friend függvények használata amúgy kerülendő, mert pont a private adatrejtési dolgát tesszük semmissé vele
34. Hogyan lehet operátorokat túlterhelni?
http://www.hotdog.hu/cxabfimjdo/objektum-orientalt-progr/operator-atdefinialas-tulterheles-overloading <= nagyon hasznos
Túlterhelés azt jelenti, hogy definiáljuk, hogy az általunk létrehozott osztályokra pl a + jel mit jelentsen
A közönséges függvényekhez hasonlóan a legtöbb operátort is túl lehet terhelni, amely a felhasználói típusok kényelmesebb használatát teszi lehetővé(jellemző például az <<(eltoló) operátor túlterhelése, melyet a kimeneti folyamok használnak kimenetként). Értékadó(=, += stb.), &(címe) operátort csak tagfüggvényként lehet megírni, minden mást érdemesebb globálisként deklarálni, ha lehet(ha nem kell hozzáférniük a tagokhoz).
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)
http://www.nagyzsolt.hu/prog2/ea/prog2_eloadas7.pdf
35. Ismertesse a kétoperandusú operátor, tagfüggvénnyel történő túlterhelését!
36. Ismertesse a kétoperandusú operátor, friend függvénnyel történő túlterhelését!
A friend, mint a neve is mondja, barát függvényt jelent, azaz elérheti
az osztály privát és védett tagjait is. Egyetlen dolog, amit tennünk
kell az, hogy deklaráljuk abban az osztályban, amelyiknek a tagjait
el akarjuk érni, hogy barát függvényrıl van szó. Ez így néz ki:
class Pont
{
friend Pont operator + (Pont t1, Pont t2);
private:
int x,y;
public:
Pont() {x=0;y=0;}
Pont(int a, int b) {x=a; y=b;}
};
Pont operator + (Pont t1, Pont t2)
{return Pont(t1.x+t2.x,t1.y+t2.y);}
Így már szépen működik, de ügyeljünk arra, hogy a friend függvényeket
csak módjával használjuk.
37. Ismertesse az egyoperandusú előtag operátor, tagfüggvénnyel történő túlterhelését!
Ha @ egyoperandusú előtagoperátor, tagfüggvénnyel definiált akkor
@op1a megfelelő hívás op1.operator@();
complex operator++(){re+=1; im+=1; return* this;}//előtag
38. Ismertesse az egyoperandusú utótag operátor, tagfüggvénnyel történő túlterhelését!
Ha @ egyoperandusú utótagoperátor, tagfüggvénnyel definiált akkor
op1@ a megfelelő hívás op1.operator@(int dummy)
complex operator++(int){//utótag
complex seged(re,im);
re+=1; im+=1; return seged;
}
39. Ismertesse az egyoperandusú előtag operátor, friend függvénnyel történő túlterhelését!
Ha @ egyoperandusú előtagoperátor friend függvénnyel definiált, akkor
@op1 a megfelelő hívás operator@(op1);
complex operator--(complex & x) {// előtag
x.re-=1; x.im-=1; return x;
}
40. Ismertesse az egyoperandusú utótag operátor, friend függvénnyel történő túlterhelését!
Ha @ egyoperandusú utótagoperátor friendfüggvénnyel definiált, akkor
op1@ a megfelelő hívásoperator@(op1, int dummy)
complex operator -- (complex & x, int) {// utótag
complex seged(x.re,x.im);
x.re-=1; x.im-=1; return seged;
}
41. Osztályok egybeépítésekor mit nevezünk kompozíciónak?
A C++ programozási nyelv egyik nagy előnye a kód újrafelhasználás támogatása. Cben
csak azt lehetett tenni, hogy lemásoltuk a forráskódot majd módosítottuk. A C++
nyelv két új lehetőséget is biztosít a kód újrafelhasználás támogatására. A megoldások
az osztály fogalmát használják. Úgy építünk fel új kódot hogy az eredeti kódhoz
hozzá sem nyúlunk, hanem azt valamilyen módon újrahasznosítjuk. Az első lehetőség
a kompozíció, ahol az új osztály már létező osztályokból áll. A második lehetőség
ennél "árnyaltabb" megoldás ahol egy új típust hozunk létre és ahhoz adunk hozzá új
kódot, de az eredeti kódhoz nem nyúlunk.
A kompozíció olyan aggregáció, amikor a rész szorosan hozzátartozik az egészhez. A részek
nem élik túl az egészet. Például az emberi agy szorosan hozzátartozik az emberhez.
//Kompozíció tagobjektum (has a reláció)
http://e-oktat.pmmf.hu/webgui/www/uploads/images/1501/010-c-c-9.pdf
42. Osztályok egybeépítésekor mit nevezünk aggregációnak?
Rész-egész kapcsolat. A részek alkotják az egészet. Például az autó motor, váz és
kerekek aggregációja. A részek túlélhetik az egészet.
//Aggregáció az osztályból kimutató hivatkozások
43.Mi az öröklődés célja programozáskor?
Olyan osztályok között értelmezett viszony, amely segítségével egy általánosabb
típusból (ősosztály) egy sajátosabb típust tudunk létrehozni (utódosztály). Az
utódosztály adatokat és műveleteket (viselkedésmódot) örököl, kiegészíti ezeket
saját adatokkal és műveletekkel, illetve felülírhat bizonyos műveleteket. A kód
újrafelhasználásának egyik módja. Megkülönböztetünk egyszeres és többszörös
örökítést.
Tehát:
Az
öröklődés segítségével lehetőségünk van felhasználni egy megírt osztály
adatstruktúrájának felhasználására a klasszikus copy/paste metódus nélkül.
Programkódunk átláthatóbb lesz, mert nem lesznek benne kódkettőzések.
Használhatjuk a virtuális függvényeket, mely szintén megkönnyíti és gyorsabbá
teszi a programozást, mert mindig az aktuális feladatnak megfelelő kódot fogja
használni a fordító.
44.Mit nevezünk közvetlen bázisosztálynak?
Egy osztálynak közvetlen bázisosztálya egy másik, ha abból közvetlenül származik.
45.Mit nevezünk közvetett bázisosztálynak?
Egy osztálynak közvetett bázisosztálya egy másik, ha abból közvetetten származik, pl ha az állatból származik a madár, amiből a pacsirta, a pacsirtának közvetlen bázisosztálya a madár, de közvetett az állat osztály.
46.Mely osztályelemek öröklődnek és melyek nem az öröklés során?
Public:
Alap.oszt.elér.: |
Bázis függvény.: |
Leszármazott függvény.: |
Leszármazott objektum: |
Public: |
Igen |
Igen |
Igen |
Protected: |
Igen |
Igen |
Nem |
Private: |
Igen |
Nem |
Nem |
Protected/Private:
Alap.oszt.elér.: |
Bázis függvény: |
Leszármazott függvény.: |
Leszármazott objektum: |
Public: |
Igen |
Igen |
Nem |
Protected: |
Igen |
Igen |
Nem |
Private: |
Igen |
Nem |
Nem |
Ide inkább ez a megfelelő ábra:
47. Hogyan adjuk meg az osztály definíciójakor a bázisosztály(oka)t?
class Állat {...}
class Madár : Állat {...}
48.Milyen szerepe van a protected osztálytagoknak (tagfüggvényeknek) az öröklés során?
az alaposztályban és a leszármazott osztályban elérhető, máshol nem.
49. Hogyan változik a különböző tagok elérhetősége public, protected és private öröklődés esetén?
A public öröklődés
Ős → Utód
public → public
protected → protected
private → −
protected
Ős → Utód
public → protected
protected → protected
private → −
private
Ős → Utód
public → private
protected → private
private → −
50. Hogyan valósítható meg a többszörös öröklődés C++-ban?
class anya
{
string haj;
string szem;
};
class apa
{
string haj;
string szem;
};
class kölyök: apa, anya
{
// Itt jonnek a 'child'-ra jellemzo
// ujabb tulajdonsagok mezoi.
};
51.Mit nevezünk polimorfizmusnak öröklődés során?
A virtuális függvényeken keresztül elérhetjük az objektum-orientált programozás másik fontos tulajdonságát a polimorfizmust, vagy többalakúságot. Ez azt jelenti, hogy egy utasítással több különböző műveletet is végre tudunk hajtani. Hogy ezen műveletek közül melyik jön létre mindig attól függ, hogy a pointerünk melyik objektumra mutat. A virtuális függvények használatával a programkódot nem kell minden esetben módosítanunk, ha új származtatott osztályt használunk, és a programkódunk rövidebb is lesz (nem kell minden esetben konkrétan meghatározzuk a fordító számára, hogy a pointer éppen melyik objektumra mutat).
A többrétûség (vagy sokalakúság, sokoldalúság) a C++-ban azt jelenti, hogy egy adott õstípusból származtatott további típusok természetesen öröklik az õstípus minden mezõjét, így a függvénymezõket is. De az evolúció során a tulajdonságok egyre módosulnak, azaz például egy öröklött függvénymezõ nevében ugyan nem változik egy leszármazottban, de esetleg már egy kicsit (vagy éppen nagyon) másképp viselkedik. Ezt a C++-ban a legflexibilisebb módon az ún. virtuális függvények (virtual functions) teszik lehetõvé. A virtuális függvények biztosítják, hogy egy adott osztály-hierarchiában (származási fán) egy adott függvény különbözõ verziói létezhessenek úgy, hogy csak a kész program futása során derül, hogy ezek közül éppen melyiket kell végrehajtásra meghívni.
http://www.codexonline.hu/CodeX5/alap/CPP/oop/cikkoo2.htm
52.Mit nevezünk virtuális tagfüggvénynek?
Virtuális függvények segítségével a származtatott osztályban az alaposztály virtuális függvényeit fölül lehet definiálni. Ha az alaposztály (ős) meghívja egy virtuális függvényét, akkor valójában a származtatott osztály függvényét fogja használni. Virtuális függvények hívása csak futási időben értékelhető ki, mert akkor ismert az objektum típusa.
A
virtuális függvényeken keresztül elérhetjük az objektum-orientált programozás
másik fontos tulajdonságát a polimorfizmust, vagy többalakúságot.
53. Hogyan lehet tisztán virtuális tagfüggvényt definiálni?
Egy osztálynak lehetnek tisztán virtuális (pure virtual) függvényei is, vagyis a bázisosztályban nem adunk meg semmiféle megvalósítást
Egy vitruális függvény az "=0" értékadástól lesz tisztán virtuális
függvény
Példa:
class CAlakzat
{
public:
virtual void Forgat(double) = 0;
virtual void Rajzol() = 0;
// ...
};
54.Mit nevezünk absztrakt osztálynak?
Absztakció ~ Elvonatkoztatás. Segítségével privát implementációkat rejthetünk el egy nyilvános
interfész mögé.
Példa: java.util csomagban List interfész és az interfészt implementáló
ArrayList, illetve LinkedList osztályok. Az absztrakció lehetővé teszi, hogy
mindkét osztály példányait ugyanazon List interfész műveletein keresztül
kezeljük.
Az elvont, vagy absztrakt osztályok átmenetet képeznek a hagyományos osztályok és az osztályokat meghatározó felületek között. Ez azt jelenti, hogy egy absztrakt osztály egyaránt tartalmaz kidolgozott, törzzsel rendelkező tagfüggvényeket, és előre nem meghatározott tagfüggvényeket, melyeket majd az osztályból származtatott alosztály fog részletesen definiálni. Az absztrakt osztály ily módon hagyományos értelemben vett osztályként és a tőle öröklő alosztályok interfészeként egyszerre tölt be funkciót.
Absztrakt osztály (elvont osztály, abstract class)
-Legalább egy tisztán virtuális függvénnyel rendelkezik
-Nem példányosítható
Absztrakt osztályok használata
-Az absztrakt osztályokat felületként (interface)
-Az absztrakt osztályokat más osztályok bázisosztályaként
Szerintem: Absztrakt osztály az az osztály, ami csak tisztán virtuális fv-ekből áll, de legalább egy tisztán viruális fv-ből.
55. Ismertesse a virtuális metódus táblázat működését!
•A késői kötés egy „keresés”-t jelent, meg kell határozni a
ténylegesen meghívandó metódust
• A cél az, hogy ez a keresés a lehető legegyszerűbb kóddal, a
lehető leggyorsabban megvalósuljon
• Ehhez egy plusz táblázat felépítése és megtartása szükséges: a
Virtuális Metódus Táblázat (VMT)
Ezen táblázat mindig egy osztályhoz tartozik
• A VMT tábla induláskor megegyezik az ősének a VMT-jével (ha
nincs ős, akkor induláskor üres)
• Ha az osztályban bevezetünk egy új virtuális metódust a „virtual”
kulcsszóval, akkor ezen metódus bekerül a táblázatba (a végére)
• Ha az osztályban felüldefiniáltunk egy már létező virtuális
metódust az „override” kulcsszóval, akkor a táblázatba ezen
bejegyzés kicserélődik az új metódusra
• A táblázatban a metódusok indításához szükséges információk
vannak eltárolva (pl. a metódusok memóriacímei, amely alapján
azokat el lehet indítani)
Tehát:
A virtuálismetódus úgy müködik, hogy amelyik osztályban deklarálva (A) van, abból az osztályból létrejött objektumnak a VMT-je (VirtuálisMetódus Táblázat) tartalmazni fogja, tehát meghivható. Ha ebből az osztályból örököltetünk egy új osztályt (object(B)), akkor örökli az összes tulajdonságot. De ha az új osztályban nem írjuk felül a virtuálismetódust, ami ugye az A-ban van, akkor az meghivható, de az A hajtja végre, mert ugye neki nincs olyan deklarálva!
Ha A-ból öröklött virtuálismetódust felülírjuk (override) és jelezzük, hogy "inherited metódus();", akkor először a szülő osztály metódusa fut le, aztán a gyermekben lévő metódus! Ha nem hivatkozunk a szülő metódusára, akkor pedig elfedjük a szülő metódusát, mintha nem is lenne!
Persze csak akkor kell virtuálisnak deklarálni, ha a gyermek osztályban felül szeretnénk írni!
56.Mi a virtuális alaposztályok használatának módja és értelme?
Mi az értelme:
• Többszörös elérés az öröklési gráfon.
Miért nem vonja össze a fordító ?
• A nevek ütközése az öröklés megismert
szabályai alapján még nem jelent bajt.
• Lehet hogy szándékos az ütközés.
• Automatikus összevonás esetén a
kompatibilitás veszélybe kerülhet.
-Alaposztály adattagjai nem épülnek be a
származtatott osztály adattagjaiba. A
virtuális függvényekhez hasonlóan
indirekt elérésűek lesznek.
- Az alaposztály konstruktorát nem az első
származtatott osztály konstruktora fogja
hívni, hanem az öröklési lánc legvégén
szereplő osztály konstruktora.
Konstruktor feladatai
• Öröklési lánc végén hívja a virtuális
alaposztályok konstruktorait.
• Hívja a közvetlen, nem virtuális
alaposztályok konstruktorait.
• Létrehozza a saját részt:
– beállítja a virtuális alaposztály mutatóit
– beállítja a virtuális függvények mutatóit
– hívja a tartalmazott objektumok konstruktorait
– végrehajtja a programozott törzset
Destruktor feladatai
• Megszünteti a saját részt:
– végrehajtja a programozott törzset
– tartalmazott objektumok destruktorainak hívása
– virtuális függvénymutatók visszaállítása
– virtuális alaposztály mutatóinak visszaállítása
• Hívja a közvetlen, nem virtuális
alaposztályok destruktorait.
• Öröklési lánc végén hívja a virtuális
alaposztályok destruktorait.
http://www.tankonyvtar.hu/hu/tartalom/tkt/objektum-orientalt/ch06s07.html -> Ctrl+F virtuális bázis osztályok
57. Ismertesse a template osztályok használatát!
Template osztály
-Használatával nem növekedik a kód méréte
-Használatával nem növekedik a futási idő
-Template osztály létrehozása előtt érdemes nem template osztályként
letesztelni az osztályt
-Kódoslási és logikai hibák könnyebben detektálhatóak
-Egyszerűbb hibakeresés
-Tagjait ugyanúgy deklaráljuk és definiáljuk, mint a "közönséges"
osztályok esetén
-Tagjai maguk is sablonok, paramétereik pedig ugyanazok, mint a
sablon osztályéi.
-Template osztálynak lehetnek függvényei
-Template osztály függvényeinek lehetnek paraméterei:
A paraméterek lehetnek
-Típust meghatározó
template<class T, T def_val> class Cont { /* ... */ };
-Sablon típusú paramétereik
template<class C> C TVerem<C>::Pop()
Template létrehozása
Szintaxis:
template<class C> class Osztaly_Neve
{
// ...
};
template<class C>
Sablon deklarációja következik
C típusparamétert fogjuk használni
Használata:
Osztaly_Neve<char> tc;
Osztaly_Neve<int> ti;
Osztaly_Neve<Pont> tp;
typedef Osztaly_Neve<char> RovidTipus;
58.Milyen STL tárolókat ismer?
Az STL (azaz Standard
Template Library) egyik fontos
részét képezik a tárolók, azok az
adatszerkezetek, amelyek különféle tárolási stratégiákat implementálva
hatékonyan, biztonságosan, kivételbiztosan és típushelyesen képesek tárolni az
adatokat, ellentétben a C-stílusú, beépített tömbökkel és kézzel írt láncolt
adatszerkezetekkel.
STL tárolók:
-Bitset
(egy
speciális bitvektor, templateparaméterként a méretét várja, így fordítási
időben ismert, és rendkívül nagy hatékonysággal hajtja végre a bitműveleteket)
-Deque Kétvégű sor; konstans időben: elem elérése, elejére/végére beszúrás.
(A deque (double-ended queue), azaz kétvégű sor egy olyan speciális sor, amelynek az elejére és a végére is értelmezve van a push és pop művelet, ellentétben a normál sorral vagy vektorral(amelyeknél csak 1-1 végre vannak ezek megvalósítva). Biztosít indexelő operátort, amivel konstans időben érhető el tetszőleges az elem, és a vectornál valamivel hatékonyabbak a belső insert és erase metódusok, de sűrű használat esetén érdemes lehet megfontolni a list használatát.)
-List Láncolt, kétirányú lista.
(A list egy kétirányú láncolt listát bocsát a rendelkezésünkre, amellyel lineáris időben hajthatjuk végre az insert és az erase metódusokat, viszont az indexelés nem biztosított. Akkor érdemes listát használni, ha sűrűn kell az adatszerkezet belső részeit változtatni, és nem lényeges az elemek konstans idejű elérése, elég a szekvenciális. A list az elemeihez saját sort metódust biztosít, amivel hatékonyabban tudja rendezni magát, mint az STL részét képező sort algoritmus.)
-Map Kulcs-elem párok ábrázolása: kulcs -> elem.
(A map egy növekvően rendezetten tárolt asszociatív tömb, amely kulcs-adat párokat(std::pair<>) tárol, viselkedésében akár egy normál tömb. A kulcs és az adat típusa is paraméter. Az indexelés nem létező elemre új elemet hoz létre, alapértelmezett konstruktorral(ennek hiányában csak inserttel lehet létrehozás után bejuttatni elemeket), és a legtöbb tárolótól eltérően megköveteli, hogy a kulcstípushoz rendelkezésre álljon egy (szigorú részben)rendezés.)
-Set “Halmaz” Minden elem egyszer szerepelhet benne.
(A maphez hasonlóan a set (halmaz) is egy növekvően rendezett adatszerkezet, de itt csak kulcsok vannak önmagukban. Egy kulcs vagy szerepel a halmazban, vagy nem.
A maphoz hasonlóan a set is rendelkezik a kulcsismétlődést megengedő változattal (multiset), ekkor a kulcsok számosságáról lehet beszélni.)
//Multiset: “Zsák” Minden elem többször is szerepelhet benne (ez az elem multiplicitása).//
-Vector Elemek tárolása közvetlen indexelt elérésre.
(A vectort a hagyományos, C-stílusú tömb kiváltására tervezték, azzal a kiegészítéssel, hogy méretét dinamikusan változtatja szükség szerint.
Fontos specializáció a bool sablonparaméterrel létrehozott vector (vector<bool>), amely egy biten tárolja az egyes értékeket, legalább nyolcadakkorára csökkentve a méretét a vectornak, de pont a bájtonkénti címezhetőség miatt problémás indexelő operátort és speciális iterátor szükségességét okozva.)
-Valarray (A valarray a vektorhoz hasonló egydimenziós tömb, de az implementációt készítők sokkal nagyobb szabadságot kaptak az elkészítésekor, hiszen kifejezetten a nagyhatékonyságú matematikai számításokra tervezték, valamint speciális indexelési lehetőségei is vannak (sliceok).)
-Stack “verem” LIFO adatszerkezet adapter. LIFO - Last in first out, az utoljára beleírt adatot adja vissza először, mint egy doboz amibe dobáljuk a cucokat és mindig csak a legfölsőhöz férünk hozzá
(A stack, vagy verem az STL-ben egy nem önálló adatszerkezet, ráépül valamely fentebbi általánosabb tárolóra(többnyire a deque-ra), a felületét átalakítva egy veremére, mintegy burkoló osztályként(wrapper) működve.)
-Queue “sor” FIFO adatszerkezet adapter. FIFO - First in forst out, a legelőször beleírt adatot adja vissza legelőször. Mint egy cső aminek egyik végén nyomjuk befele az adatot másik végén meg ugyanebben a sorrendben olvashatjuk ki
(A sor a C++-ban, a veremhez hasonlóan, burkoló osztály, azaz a
meglévő tárolókra ráépülve biztosítja a FIFO (First In First Out) felületet. A fejállomány
tartalmazza még a Prioritásos
sort(priority_queue).)
// Priority que “prioritásos sor” Összehasonlítható elemeket tárol, a
legnagyobb vehető ki eloször.
59.Milyen adapter tárolókat ismer?
(?)
Adapter tárolók:
A stack LIFO típusú,
a queue FIFO típusú tárolók más típusú tárolót használnak egyszerűsített kezelő felülettel.
60.Mi a bejáró és hogyan használhatjuk?
algoritmusok: bejárókkal és funktorokkal paraméterezhetőek
● bejárók: a tárolt elemek elérése valamilyen sorrendben
Bejáró (iterátor): a tároló egy elemére mutat, egy mutatóhoz nagyon hasonlóan
● műveletei
○ ++ (pre- és posztfix egyaránt): a tároló következő elemére mutat
○ --: a ++ ellentéte (csak kétirányú bejáróra értelmezett)
○ * (prefix): visszaadja a mutatott elemet (hasonlóan a mutatók feloldásához)
○ ->: taghivatkozás a mutatott elemen belül, mint mutatóknál
○ véletlen elérésű bejáróknak további műveletei is vannak
● bejáró lehet konstans, ami a szokásos módon azt jelenti, hogy a mutatott érték nem változhat meg
● a tárolókhoz általában elérhető bejárók
○ begin(): a tároló első elemére mutat
○ end(): a tároló utolsó utáni elemére mutat
■ ez jelzi, hogy bejárás során a tároló végére értünk
○ rbegin(), rend(): ha visszafelé is bejárható a tároló, a tároló hátulról nézve első/utolsó utáni elemére mutat
● a bejárókat nem csak az STL algoritmusaival lehet felhasználni
61. Ismertesse a vector tároló memóriamodelljét!
-Vector (A vectort a hagyományos, C-stílusú tömb kiváltására tervezték, azzal a kiegészítéssel, hogy méretét dinamikusan változtatja szükség szerint.
Fontos specializáció a bool sablonparaméterrel létrehozott vector (vector<bool>), amely egy biten tárolja az egyes értékeket, legalább nyolcadakkorára csökkentve a méretét a vectornak, de pont a bájtonkénti címezhetőség miatt problémás indexelő operátort és speciális iterátor szükségességét okozva.)
A vector #include <vector>
•Elemek sorban (dinamikus tömbökkel megvalósítva),
•Folytonos adatterületen pointerrel és bejáróval is bejárható.
•Automatikusan növekszik és csökken a tárolási mérete.
•Az elemek könnyen elérhetők pozíció alapján (állandó idővel)
•Az elemek sorban bejárhatók (lineáris idővel)
•Elemek illeszthetők/törölhetők a végéről (konstans idővel)
•Elemek beilleszthetők és törölhetők is, azonban erre mások (deque, list) jobb időt produkálnak
•Memóriamodell
62. Ismertesse a deque tároló memóriamodelljét!
-(A deque (double-ended queue), azaz kétvégű sor egy olyan speciális sor, amelynek az elejére és a végére is értelmezve van a push és pop művelet, ellentétben a normál sorral vagy vektorral(amelyeknél csak 1-1 végre vannak ezek megvalósítva). Biztosít indexelő operátort, amivel konstans időben érhető el tetszőleges az elem, és a vectornál valamivel hatékonyabbak a belső insert és erase metódusok, de sűrű használat esetén érdemes lehet megfontolni a list használatát.)
63. Ismertesse a list tároló memóriamodelljét!
A list egy kétirányú láncolt listát bocsát a rendelkezésünkre, amellyel lineáris időben hajthatjuk végre az insert és az erase metódusokat, viszont az indexelés nem biztosított. Akkor érdemes listát használni, ha sűrűn kell az adatszerkezet belső részeit változtatni, és nem lényeges az elemek konstans idejű elérése, elég a szekvenciális. A list az elemeihez saját sort metódust biztosít, amivel hatékonyabban tudja rendezni magát, mint az STL részét képező sort algoritmus.
64. Ismertesse a stack tároló memóriamodelljét!
A stack, vagy verem az STL-ben egy nem önálló adatszerkezet, ráépül valamely fentebbi általánosabb tárolóra(többnyire a deque-ra), a felületét átalakítva egy veremére, mintegy burkoló osztályként(wrapper) működve.
65. Ismertesse a queue tároló memóriamodelljét!
Queue (A sor a C++-ban, a veremhez hasonlóan, burkoló osztály, azaz a meglévő tárolókra ráépülve biztosítja a FIFO (First In First Out) felületet. A fejállomány tartalmazza még a Prioritásos sort(priority_queue).)
66. Hogyan használhatja az algoritmusokat STL tárolók esetén?
Az algoritmus: Általánosan megvalósított függvény, amely minimális követelményt támaszt azon
adatokkal szemben, amelyeken végrehajtódik.
Algoritmusok
● az algorithm fejléc szükséges hozzá
● az algoritmusok szinte mindig egy tároló részintervallumán dolgoznak
○ ezeket egy-egy iterátor jelöli
● az algoritmusok paraméterezhetőek
○ konstans
○ logikai függvény (predikátum): tulajdonságok vizsgálatára
○ általános függvény: értékek átalakítására vagy előállítására
1. Ismertesse a nativ kód fejlesztési folyamatát.
Forditási folyamat: C forrás (text) -> preprocesszált C forrás (még mindig text) ->asm
forrás->gépi kód->linkelés->futtatható (gépi/natív) kódot tartalmazó (exe) file. File-t OS
betölti, vezérlést main() fv (linker által beállitva) megkapja.
(Mpt_ea/2)
(Nativ kód: adott processzoron futó gépi kódú program, ami adott OS-en használható.
Pl. Win32-es EXE linuxon csak emulátorban futtatható, de ott sem mindig.)
2. Mit nevezünk gépi kódú programnak ?
A gépi kód a számítástechnikában használt műveletek és adatok (általában bináris – kettes számrendszeren alapuló – vagy hexadecimális – tizenhatos számrendszeren alapuló – számokkal ábrázolt) olyan sora, amely a számítógép processzora számára közvetlen utasításként értelmezhető.
(A gépi kód az egyetlen "nyelv", amit a számítógép központi parancsvégrehajtó egysége, a processzor megért, ezért minden programozási nyelvet gépi kóddá kell alakítani ahhoz, hogy a program végrehajtható legyen. Ezt az átalakítást végzik a fordítóprogramok. Ezek az utasítások általában csak egy processzortípusra vonatkoznak, és azon belül is generációnként változhatnak (az újabb processzorokban az előzőnél több utasítás szokott lenni). Az egyes processzortípusok utasításkészletei egymással egyáltalán nem kompatibilisek. Ez azt jelenti, hogy egy másik processzorra készített programot (ez alól az operációs rendszerek se kivételek) nem tudnak végrehajtani (például Alpha-s Windows-ot nem lehet PC-kre feltenni és fordítva, vagy PC-s Linux-ot nem lehet SPARC-ra feltenni és fordítva stb.).) Újabb példa: androidos telefonra nem fogsz XP-t föltenni, mert full más a processzor. Win7/8-ból már készült ARM-es is, szóval azt esetleg
3. Ismertesse a RAD alkalmazásfejlesztés elemeit.
Wiki:
A gyors alkalmazásfejlesztés
(Rapid application development vagy RAD) egy szoftverfejlesztési eljárás. James Martin dolgozta ki a 1980-as években. A
módszertan elemei: ciklikus fejlesztés,
működő prototípusok létrehozása,
és a szoftverfejlesztést támogató számítógépes programok, például integrált fejlesztői környezetek használata
Ea: (Mpt_ea/5)
Iteratív folyamat: GUI-val megrajzolom, megírom, kipróbálom, visszamegyek a
rajzolóhoz, módositom, a kódot is, vissza a
kipróbál-ra, egyszer csak abbahagyom. Kész sosem lesz.
4. Ismertesse a Sun(Oracle) rendszerben az alkalmazások futtatását.
Nem nativ kód: adott rendszeren kell java run-time-nak lenni (VM-virtuális gép), azon képes futni a bytecode (leforditott, de
közbenső - a forrás már nem látszik, de még nem gépi kód).
(?)
5. Ismertesse a nativ kódú programfejleszés gyakori, pointerekkel kapcsolatos problémáit.
1) Pointer, ami nem a mi adatterületünkre mutat, vagy oda mutat, de elkóborol
Ilyen a tömb túlcimzése is, 5 elemű tömbnél t[5]
2) Azok a dinamikus változók, amelyekre már nem mutat pointer, mert lenulláztuk, foglalják a memóriát, de nem tudjuk őket használni, és törölni sem (van lakásom, csak a címét nem tudom).
3) void * tipus nélküli pointer, ezzel garázdálkodhatunk a memóriában (windows.h ezzel kezdődik)
(Mpt_ea /9)
char *kozepre(char* mit)
{ // itt volt egy if, ami jól működött, 80-nál hosszabb string: hiba.
int szokoz=(80-strlen(mit))/2;
char *szok=(char*) malloc(80); // 80 hoszú, de hol a VÉGJEL ?
memset(szok,' ',szokoz); // ettől lesz benne valahány szóköz, de \0 (végjel) nem.
strncat(szok,mit,strlen(mit)); // hozzáirja. először megkeresi
// a 0-t a szok-ban (valahol a memóriában, előreszaladva),
// majd odamásol a mit-ből mindent, vagyis strcat(azok,mit).
// akkor is odamásolja, ha már nem a miénk a memória.
return szok;
}
6. Ismertesse a nativ kódú programfejleszés memória allokációval kapcsolatos problémáit.
1) Azok a dinamikus változók, amelyekre már nem mutat pointer, mert lenulláztuk, foglalják a memóriát, de nem
tudjuk őket használni, és törölni sem (van lakásom, csak a címét nem tudom).
2) A szükségtelen dinamikus változók törlésekor a memória fragmentálódik, lyukak keletkeznek, igy a
használható egybefüggő terület (a tömb mindig egybefüggő kell legyen) csökken.
Azok a dinamikus változók, amelyekre már nem mutat pointer, mert lenulláztuk, foglalják
(Mpt_ea /9)
7. Ismertesse a CLR rendszert.
Common Language Runtime:
egy rendszer, amely egy „virtuális gépi kódú nyelv”-re fordított programokat
(.exe) képes futtatni.
Mpt_ea/10 :
Managed (menedzselt) kód
A program (exe fileból) nem közvetlenül a processzoron fut,
hanem egy futtató környezetben. A környezet neve:
Common Language Runtime (CLR)
8. Ismertesse a managed kód futtatási lehetőségeit.
??
Szerintem (diasor alapján):
-JIT (just in time): A CIL programot utasitásonként értelmezve: Justin-
time (JIT) fordítással / debuggolással.
Ellenőrzi a kódot, pointereket, memóriaterületeket,
objektumokat. Ha hiba van, exception keletkezik.
-AOT (ahead of time): Ahead-of-time fordítással (AOT). A CIL programot
futtatás előtt natív kóddá fordítja egy forditóprogram, a Native
Image Generator
9. Mit nevezünk CIL(régi nevén MSIL) nyelvnek ?
Leánykori nevén MSIL. Stack alapú, objektumorientált assembly nyelv, amely még szövegesen olvasható. Erre forditanak
a forditóprogramok (C++/CLR, C#, VB). Nem natív, nem fut az Intel CPU-n.
(Mpt_ea/10)
10. Ismertesse a garbage collection működését a .net rendszerben.
Automatikus szemétgyűjtés. A már nem használt objektumpéldányokat kitörli, a memóriaterületet felszabaditja, a memóriát
defragmentálja. Először a LISP nyelvben jelent meg.
(Mpt_ea/11)
11. Mit nevezünk a .net rendszerben „assembly”-nek ? Hol tároljuk ezeket ?
Előre elkészített „gyártószerszámok”, amelyekkel objektumokat hozhatunk létre. Lehetnek Windows-os vezérlők, filekezelők, tömbök, vagy szemétgyűjtők is. „Desinger” GUI-val is megrajzolhatjuk, vagy forrásprogramból is létre lehet hozni őket. A Designer is egy forrásprogramot ír meg, ami elé odateszi megjegyzésben, hogy „Ne módositsd”. A VS Designer
által kezelt assembly-ket „Control”-oknak (vezérlő) nevezik. A vezérlőknek tulajdonságaik (változók), és eseményeik
(függvények - metódus) vannak, és ezeken keresztül kommunikálnak a külvilággal (felhasználó, operációs rendszer). A
designerben a tulajdonság és az esemény külön fülön jelenik meg. Base Class Library tartalmazza őket.
(mpt_ea/12)
12. Ismertesse a .net rendszer részeit.
Common Language Infrastructure
A .NET Framework alapját a CLI vagyis a Common Language Infrastructure képezi. Ez nem más mint azon szabályok halmaza, amelyek leírnak egy nyelvfüggetlen fejlesztői környezetet, a futtatókörnyezetet, típusrendszert stb. A .NET Framework implementációját CLR-nek, Common Language Runtime-nak hívják. A CLI maga is négy fő részre oszlik.
A CLS a CLI része. Azokat a szabályokat írja le, amelyeket a CLI kompatibilis nyelveknek be kell tartania. Érdekesség, hogy a legtöbb .NET nyelv - pl. a C# - tartalmaz olyan elemeket, amelyek nem felelnek meg a CLS specifikációnak (pl. a CLS nem engedi meg ulong típusú paraméterek használatát, míg a C# igen).
A CTS a CLI azon része, amely a típusokat, azok memóriabeli reprezentációját illetve egymással való interakcióját írja le. A .NET minden nyelve ugyanazt a típusrendszert használja, bár az egyes típusok megnevezése nyelvfüggő (de végeredményben mindig ugyanarról a típusról van szó).
A CLR vagy VES (Virtual Execution System) a CLI nyelven megírt programok betöltéséért és végrehajtásáért felel. Felelősséggel tartozik továbbá a memóriamenedzsmentért, kivételkezelésért illetve a kódbiztonságért is (hogy a fontosabbakat említsük).
A CIL (korábban MSIL) egy ún. köztes kód. Minden CLI nyelvben megírt program erre a kódra fordítódik le (ellentétben a hagyományos nyelvek natív kódjától). Ezt a kódot a tényleges futtatáskor az ún. jitter (Just in time compiler) fordítja le natív kódra, amelyet a processzor már tud kezelni. A CIL hasonlít a Java bytekódjára.
(itt ezt kérdezik??)
remélhetőleg :)
13. Ismertesse az alap memóriakezelő műveleteket (helyfoglalás, hivatkozás, felszabaditás) a K&R C-ben, a C++-ban, és a C++/CLI-ben.
Helyfoglalás
C malloc() C++ new C++/CLI gcnew
felszabadítás
C free() C++ ~ C++/CLI automatikus/~/ !
14. Ismertesse a „C++ Interop” fogalmat. Milyen adatokat és függvényeket tartalmazhat egy ilyen projekt ? Hova kell állitani ehhez a VS „common language runtime support” opcióját ?
http://blog.naiznoiz.com/2008/01/cc-interop-a-simple-example
http://www.codeproject.com/Articles/16987/C-Interop-is-for-the-Performance-Minded-Developer
This technology allows programmers to intermingle managed & unmanaged code with the ability to call native functions directly, all without having to add any additional code. Through the judicious use of #pragma (un)managed, the developer can selectively decide on a function by function basis which are managed & which are native. Mixed and native code assemblies alike can be compiled using the /clr compiler switch. This will provide accessibility to the .NET platform as well as enabling interoperability support. This degree of flexibility should be enough to entice most programmers but there is more.
(mpt_ea/15):
Tisztán managed kód. Adatból nativot is, (a C# nem) függvényből csak managed-et tartalmazhat.
“common language runtime support”-t common language runtime support-ra kell állítani
15. Ismertesse a „referencia osztály” fogalmát. Irjon példát referencia osztály példányositására, egy beépitett, ismertetett osztályt felhasználva.
(mpt_ea/16):
A managed halmon lévő osztályt referencia oszálynak kell deklarálni. A referencia osztályra handle (^) hivatkozik.
A létrehozása gcnewoperátorral történik. (A kalap sosem volt a hatványozás jele. Bináris kizáró vagy volt régen.)
16. Ismertesse a refencia osztály példányának létrehozó operátorát. Létezik-e megszüntető operátor a referencia osztályhoz ?
gcnew, nincs megszüntető operátor, a megszüntetést a garbage collector végzi.
17. Mivel jelezzük a forditónak, hogy nativ kódú függvény következik ? Mivel jelezzük, ha managed kódú ?
#pragma managed
#pragma unmanaged
18. Ismertesse a referencia osztály jellemzőit. Mutasson rá a nativ C++-hez képesti különbségekre és bővitésekre.
Többalakúság jellemzi, örököltetni lehet belőle
Referencia osztályban lehet (C++ szabványból)
-Adattag (public,private,protected)
-Konstruktorok (overload-dal)
-Metódusok (overload-dal)
-Operátor definició művelethez, pl. operator +
-Operátor konverziós művelethez, pl. operator string()
-Destruktor ~ jellel
-Öröklés, csak public tipussal, csak 1 őstől
-Abstract: tisztán virtuális tagfüggvény =0
-Osztályon belül is lehet osztály (nested class)
CLI-s bővitések, változtatások:
* helyett ^
& helyett %
-> itt is ->
Property készithető a bezárt adattaghoz (get:
kiolvasásához, set : beállitásához). A felhasználó úgy látja,
mintha public adattag lenne. A property programutasitásokat
tartalmazhat, és tipusa is van.
Finalizer metódus ! jellel, destruktor is hivhatja, GC is
Abstract-ot, override-t kötelező kiirni
Alaphelyzetben private elérés
19. Ismertesse a referencia osztály „property”-jét. Mi az előnye a property-nek a c++ class adatelérő tagfüggvényéhez képest ?
Property készithető a bezárt adattaghoz (get: kiolvasásához, set : beállitásához). A felhasználó úgy látja, mintha public adattag lenne. A property programutasitásokat tartalmazhat, és tipusa is van.Finalizer metódus ! jellel, destruktor is hivhatja, GC is
Abstract-ot, override-t kötelező kiirni. Alaphelyzetben private elérés
Skaláris property: egy függvény a bezárt adathoz
Triviális property: tartalmazza az adatot
Virtuális property: override lehet az örökösben
Többdimenziós property: [ ] közt index.
Gondolom ha később jövünk rá, hogy mégis protectedé kéne tenni az adott típust, akkor a get/set-es megoldással a program többi része ezt nem fogja észrevenni. + ha többen dolgozunk egy projekten, akkor egyszerűbb azt mondani, hogy van nekem egy terület változóm, olvasd-módosítsd azt, minthogy van egy olvasterület() és egy írterület() függvényem, hivogasd azt.
20. Ismertesse a referencia osztály „finalizer” metódusát. Mi a fő különbség a destructor és a finalizer közt ?
http://sanjaysainitech.blogspot.hu/2007/06/difference-between-destructor-dispose.html
destructor managed erőforrások felszabadítására való, a finalizer az unmanaged-ekre
21. Ismertesse a referencia osztály „abstract” és „sealed” kulcsszavait.
(?)
Sealed: az osztály(stb)ból nem tudunk örökösöket származtatni, csak példányokat.
Ilyen pl. a public sealed class String
Abstract: Ha egy virtuális függvénynek nincs kifejtése, abstract-nak kell dekralálni: virtual tipus függvénynév() abstract; vagy virtual tipus függvénynév() =0; (az =0 a szabvány c++, az abstract =0-nak lett definiálva)
22. Ismertesse az interface osztály készitésének alapelveit.
Referencia helyett interface class/struct (teljesen ugyanazt jelenti). Az interface összes tagja (adattagok, metódusok, események, property-k) elérése public. A metódusok, property-k nem kifejthetőek (abstract), az adatok csak statikusak lehetnek. Konstruktor sem definiálható. Az interface nem példányositható, csak ref/value class/struct hozható létre belőle, öröklődéssel. Az interface-ből másik interface is örököltethető. Egy származtatott (derived ) ref class-nak akárhány interface lehet a szülő (base) class-a.
Statikus adattagokat és konstruktort is tartalmazhat
??/Joe diasorából, talán erre gondolt?
23. Ismertesse a String referencia osztály alkalmazását.
A C++ string típus mintájára készült egy System::String osztály, szövegek tárolására.
public sealed ref class String, Member of System
A szöveget Unicode karakterek (wchar_t) sorozatával tároljuk (ékezettel semmi probléma nincs, L betű kirakása a konstans elé). Alapértelmezett konstruktora 0 hosszú szöveget (””) hoz létre. Többi konstruktora lehetővé teszi, hogy char *-ból, nativ string-ből, wchar_t-ből, egy stringeket tartalmazó tömbből hozzuk létre. Miután ref class, handle-t (^) készitünk hozzá, és tulajdonságait, metódusait ->-lal érjük el.
String->Length hossz
String[hanyadik] karakter (0.. mint a tömböknél), kiolvasáshoz.
String->Substring(hányadiktól, mennyit) részlet kiemelése
String->Split(delimiter) : a stringet szétszedi az elválasztóval (delimiter) a benne található szavak tömbjére.
miben->IndexOf(mit) keresés. 0... kezd poz. case sensitive -1: nincs
String->ToString() is létezik, örökölték. Viszont nincs char*-ra, vagy nativ string-re konvertáló metódus.
Szabványos operátorok: ==, !=, +, +=.
24. Ismertesse a Convert osztály alkalmazását és gyakran használt tagfüggvényeit. Mire kell ügyelni a szöveg->szám konverzióknál ?
Leggyakoribb alkalmazása a szám<->String konverzió. Convert::ToXXX formátumban létezik nagyszámú overload, hogy szinte minden adattipushoz legyen Convert::ToString pl.
A konverzió figyelembe veszi a nyelvi beállitásokat is, pl. „1.5” magyar területi beállitásokkal hibát dob, ha ToDouble-é konvertáljuk. A program szövegében mindig tizedespont szerepel. Az adatokat tartalmazó osztályoknak is van Format() és Parse() metódusa, amelyek paraméterezett konverziót
valósithatnak meg, pl. hexadecimális számokra.
Tagfügvények?
25. Ismertesse az array template alkalmazását.
Készitettek egy általános tömbdefiniciót, amiből a felhasználó gyárthat a szükséges adattipussal referenciát. Többdimenziós tömbökre is használható. A tömb elemeinek elérése a hagyományos [ és ] operátorokkal történik, értékadáshoz is.
Deklaráció: cli::array<tipus,dimenzió=1>^ tömbnév; a dimenzió default paraméter, értéke 1. A ^ a ref class jele.
A tömbnek helyet kell foglalni használat előtt a gcnew operátorral (ref class esetén gcnew).
Tulajdonsága: Length (hossza, a függvénynek átadott tömbnél nem kell méret, a for kisebb jellel nem cimez ki a tömbből).
Array:: metódusok: Clear(tömb,honnan,mennyit) törlés 0,false,null (tipustól függően).
Resize(tömb, új méret) átméretezés, bővülés esetén a régi elemek után 0-kkal tölti fel
Sort(tömb) sorbarendezés. Megadhatunk kulcsokat és összehasonlitó függvényt is.
CopyTo(céltömb,kezdőindex) elemek másolása. Az = operátor csak a referenciát duplikálja, ha a tömb adata megváltozik, a másik felől elérve is megváltozik. Hasonlóan az == is azt jelzi, hogy a két referencia ugyanaz, és nem az elemeket. Ha a tipus, amiből a tömböt készitjük, egy másik referencia osztály (pl. String^) sormintát kapunk.
A tömb elemeit felsorolva is megadhatjuk a C++-ban szokásos módon. Többdimenziós elérés:
E[0,0]=1; E[0,1]=0; E[1,0]=0; E[1,1]=1; // 2x2-es egységmátrix.
26. Ismertesse a „Form” vezérlő gyakran használt tulajdonságait és eseményeit.
tulajdonságok: pl. háttérszín
események:
onLoad() a programunk inditásakor lefut, amikor a form még nem jelent meg. Erre az eseményre tesszük a programunk inicializáló részét (kezdeti értékadások, vezérlők felprogramozása, referencia osztályok létrehozása gcnew-val stb). Rajzolni a Graphics osztállyal még nem szabad, mert még nincs mire rajzolni. Alapértelmezett esemény a Designer-ben.
onClick() ha rákattintunk akkor fut le
Paint() (???? - lehet más a neve) ha átméretezés vagy egyéb dolog miatt újra kell rajzolni, akkor fut le
// A Form egy container, tehát példányai egyéb objektumokat tartalmazhatnak (pl. TextBox).
// Resize, Paint: a form méretét a felhasználó megváltoztatta, illetve a form-on lévő ábrát újra kell //rajzolni (festeni).
27. Ismertesse a szöveg ki/bemenetre használható vezérlőket.
Label: szöveg (String^) kiiratására szolgál. A Text tulajdonsága tartalmazza a szöveget.
Eseménye is van: Click, de nem szokás megirni. Ha számot akarunk megjeleniteni, Convert::ToString() szükséges.
TextBox: szöveg (String^) bevitelére használható (akkor is, ha számot irtunk oda). Text tulajdonsága tartalmazza a szövegét,
amelyet programból is átirhatunk, és a felhasználó is átirhat. Eseménye is van: TextChanged, amely minden változtatás után (karakterenként) lefut.
28. Ismertesse a programrészlet (függvény) futtatására használható vezérlőket.
Button: parancsgomb. Kevés számú programfunckiónál alkalmazzuk (a funkció lehet bonyolult is). Text a felirata, Click az esemény, amely a gombra való kattintáskor lefut. Click az alapértelmezett eseménye.
!!(Mutató (pointer): nem vezérlő. A már meglévő vezérlők kiválasztására való.)
29. Ismertesse a logikai adatbevitelre használható vezérlőket.
CheckBox: kijelölőnégyzet. Text tulajdonság a melléirt szöveg, Checked, ha a pipát bekapcsoltuk. Létezik szürke pipa is, amit csak programból állithatunk be, viszont checked-nek minősül! Amennyiben a form-on több is van belőle, ezek függetlenek egymástól.
Eseménye is van: CheckedChanged lefut, amikor a felhasználó megváltoztatja.
RadioButton: kör alakú kijelölő. CheckBox-hoz hasonló, de egy konténerobjektumon belül csak egy lehet aktiv. Amikor az egyikre odakerül a kijelölő kör (programból, vagy a felhasználó által), az előzőről (az összes többiről) lekerül (Checked=false).
Ha egyszerre két listából is kell választani RadioButtonokkal, akkor készitünk GroupBox-ot, minden box-ban egy radiobutton lehet aktiv. A konténerek csoportjában találjuk.
30. Ismertesse az egész szám intervallumból történő bevitelére használható vezérlőket (nem a Textbox-ra és valami if-es programrészletre gondoltunk).
HScrollBar és VScrollBar csúszkák. Feliratuk nincs. Az aktuális érték, ahol a csúszka áll, Value, ez a Minimum és a Maximum közé esik elméletben. (The maximum value that can be
reached through user interaction is equal to 1 plus the Maximum property value minus the LargeChange property value.)
A LargeChange és SmallChange általunk beállitott értékek, a csúszka mozgatásakor Change esemény fut le.
NumericUpDown: egy egész szám vihető be vele (Value), a Minimum és Maximum érték közt. Esemény: ValueChanged
31. Ismertesse a bitmap-es kép megjelenitésére alkalmas vezérlőt, és gyakran használt tulajdonságait.
PictureBox: pixelgrafikus képek megjelenitésére. Image tulajdonsága tartalmazza a megjelenitendő Bitmap referenciáját.
Height, WidthTulajdonságai a méreteit, Left, Top tulajdonságai az ablak bal szélétől és tetejétől mért távolságát pixelben
32. Ismertesse a menük tipusait a megjelenités helye alapján. Mikor célszerű menüt alkalmazni ?
Menük. Több programfunkció esetén a funkciók elinditására hierarchikus szerkezetben menü készithető. A menü elemei a buttonhoz hasonlitanak (Text a felirat, Click a kiválasztás). Egyes menüelemek elé kijelölő pipa is rakható, másoknak nem szövege van, hanem bitmap képe. Az elemek közé Separator rakható. Menüelem lehet még textbox, progress bar, sőt combobox is.
Először a menüszalagot kell megtervezni, majd a ráhelyezett menüelemeket.
MenuStrip: az ablak tetején szöveges menüelemek. Ilyen a File..Súgó menüje a programoknak (már amelyiknek még van…)
ContextMenuStrip: alaphelyzetben nem látszik, nekünk kell megjeleniteni pl. a form_mousedown eseményben, X,Y koordinátákon.
ToolStrip: az ablak felső részén grafikus parancsgombokat tartalmaz.
StatusStrip: az ablak alján egysoros állapotsor. Nem szokás rákattintani. Sokszor tartalmaz progressBar-t.
33. Ismertesse a dialógus és üzenetablakok használati lehetőségeit.
Néhány vezérlő nem mindig látszik, csak ha a programból meghivjuk. Ilyen pl. a fileok megnyitását és mentését tartalmazó dialógusablakok: OpenFileDialog, SaveFileDialog, PrintPreviewDialog.
Az üzenetablakot meg sem kell rajzolni, mert a Windows biztositja, csak meghivni a statikus metódussal.
34. Ismertesse a timer vezérlő alkalmazását.
A Timer nem látható vezérlő. Periodikus futtatásra szolgál. Az Interval tulajdonságában megadott idő (ms) letelte után lefuttatja a Tick eseményét. Nem használható várakoztatásra, arra a Sleep() függvény kell. Bár azért ezzel is meg lehet oldani, de a Sleep() az igazi
35. Ismertesse ábrával a bináris file-ok kezelésénél használt osztályokat a .net rendszerben.
FileStream^ fs = gcnew FileStream(fileName, FileMode::Open);
BinaryReader^ br = gcnew
BinaryReader(fs);
while (br->BaseStream->Position < br->BaseStream->Length)
Console::WriteLine(br->ReadInt32().ToString());
vagy
FileStream^ fs = gcnew FileStream("data.bin",
FileMode::Create);
BinaryWriter^ w = gcnew
BinaryWriter(fs);
w->Write(data[i]);
http://msdn.microsoft.com/en-us/library/vstudio/3f3t7tke.aspx
http://msdn.microsoft.com/en-us/library/vstudio/67czzkst(v=vs.100).aspx
36. Ismertesse a textfile-ok kezeléséhez használható osztályokat a .net rendszerben.
Szekvenciális (szöveg) fileokhoz a StreamReader és
StreamWriter használható. Nem szükséges létrehozni a
FileStream-et, ugyanis kizárólagosan használja, igy létrehozza
magának, ha kell. A Writer-nél Append lehetőség is van.
ReadLine(),WriteLine(…) metódusok: egy sor i/o String-be.
EndOfStream tulajdonság a file végén igaz.
37. Ismertesse az általános internetes kommunikáció adattípusait és megvalósítását a .net rendszerben.
internetes kapcsolat=szekvenciális file. A kapcsolat felvétele után amit az egyik oldalon write-tal beleirunk, a
másik oldal kiolvashatja read-del.
• Lehet a socket-re is épiteni (általános kommunikáció: using namespace System::Net::Sockets;), vagy adott
alkalmazásra (pl gyári böngésző vezérlő)
// globals
TcpClient^ client;
NetworkStream^ stream;
cli::array<Byte>^data;
bool Connect( String^ server, Int32 port ) // MSDN-es példa alapján
{
try
{
client = gcnew TcpClient( server,port ); // kapcsolódj.
stream = client->GetStream(); // a szekvenciális file.
}
catch ( ArgumentNullException^ e ) // ha nincs paraméter:
{
MessageBox::Show( "ArgumentNullException:"+ e->Message );
return false;
}
catch ( SocketException^ e ) // ha nem tudunk kapcsolódni
{
MessageBox::Show( "SocketException: "+ e->Message );
return false;
}
return true; // siker !!!
}
38. Ismertesse a .net alapvető grafikus lehetőségeit, a felhasznált koordináta rendszert, a vonalhúzáshoz szükséges osztályokat.
A grafikához természetesen van egy ref class, a neve Graphics. Rajzolni toll-lal lehet, ennek a neve Pen.
Több vezérlő tud grafikát késziteni (CreateGraphics()), célszerű a Form-ot választani (this->CreateGraphics();). A grafikát csak
meglévő form-nál szabad elkésziteni (nem a Form_Load-ban), button-ra, timer_re, esetleg a form_paint-ra programozva.
A tollat gcnew-val készíthetjük bárhol, a konstruktora egy színt kér, és a Color tulajdonsága bármikor megváltoztatható.
Egyéb beállitásai is vannak: vonaltipus, vastagság, minta, sőt transzformációs mátrix (Drawing2D::Matrix) is adható hozzá.
Pen^ toll;// ezzel rajzolunk System::Drawing::Pen
toll = gcnew Pen(System::Drawing::Color::Blue); // kék toll
Alap rajzoló metódusok:
DrawLine a toll után vagy két pont, vagy négy koordináta megadása után vonalat húz.
m2majatt:
Itt nem fv(&a) kéne? Hisz ha fv(a)-t hívunk meg akkor az ¶m lesz a-val egyenlő és akkor hülyeségeket csinál nem?
gaborlakosi:
nem, ez így jó, hiszen ha &a-val hívnánk meg akkor az a-ra mutató pointert inkrementálná, ami problémás lenne (egyébként hibát ad rá a visual studio)
m2majatt:
Okés, köszi szépen :D
m2majatt:
Itt a[10]-re szerintem nem hivatkozhatunk, hisz az utolsó elem a 9-edik (0,1,...,9), vagy nem?
Tamás Fehér:
az a[10] itt tényleg a 11. elemre mutat. azért nem ad hibát a program, mert heap területen a lefoglalt 10 egység utáni memóriaterület kihasználatlan, és utólag definiált +1 elemet. ha az a[] után egy b[] tömböt is lefoglalunk, akkor az a[10] már hibát ad.
U.i.: Amúgy marha jó a doksi kommentelhetősége! :D