RE: Ukazka C++ pro děti

Pavel Hudecek edizon na seznam.cz
Středa Březen 31 19:36:45 CEST 2021


Každý „úhel pohledu“, alias programovací technika je vhodný pro jiné účely. Pro matematické operace je to celkem jedno, jen je jasné, že 
X = (4+a/1280)*b^3
je poněkud přehlednější než 50 řádků kódu v assembleru a poněkud snadněji se to bude upravovat.

Jiná věc je, když ten výpočet bude třeba součástí hry. Místo X pak bude třeba hracX a ten bude mít ještě Y, Z, dva úhly kam kouká, 3 složky vektoru pohybu, zdraví, počet nábojů, … a pak tam budou ještě potvoráci a ti mají podobné vlastnosti.

Snadno dojdeme k tomu, že než vytvářet 30 proměnných s názvem začínajícím hrac a 30 polí pro všechny breberáky, bude lepší udělat nějakou strukturu, která popisuje, jaký všechny vlastnosti může mít aktivní objekt v tý hře a všechny hráče a breberáky pak udělat podle něj.
Takže místo deklarace
Int hracX, hracY, hracZ, …
Int breberaciX[10], breberaciY[10], …
Uděláme strukturu
Typedef struct tObjekt {
	Int x, y, z, …
}
A potom deklaruju:
tObjekt hrac
tObjekt breberaci[10]
a pak budu pracovat s hrac.x, breberaci[6].y, … a bude to mnohem jasnější, protože seznam těch vlastnstí je na jednom místě. Jelikož C má i poitery na funkce, můžu si do tý struktury přidat i funkce a tak když hráč zmáčkne fire, vyvolá něco jako hrac.strilet(2,125,38,64)
přičemž 2 je druhá zbraň z inventáře a zbytek vektor směru.

Už tady začíná být jasné, že by to možná chtělo víc úrovní struktur, takže poloha bude třeba ve struktuře tXYZ, která obsahuje x,y,z. Takže pak můžu mít funkci, která má parametry tohoto typu, či takový typ vrací.
Takže máme hrac.poloha.x, ale to X nás už většinou nezajímá. My třeba napíšeme:
If (vzdalenost(hrac.poloha, breberaci[5].poloha) <  breberaci[5].plamen.dosah)
{
hrac.poskodit(breberaci[5].plamen.dmgPerSec).
}
Tak jsme se dostali ke strukturálnímu programování.

No ale hra je rozsáhlá, takže jí programuje 15 lidí a můžou vznikat zmatky. Proto místo místo struktury použijeme objekt, což znamená, že místo struct bude class a jinak je všechno stejný. Teda až na to, že v class můžou bejt sekce public, private, protected, friend a možná ještě něco. A já, jako autor toho class nadefinuju, který věci mám svoje a zvenku nejsou vidět, tudíž do nich kolega omylem nezasáhne a do jakých může zasahovat okolí apod.

A v případě C++ nám z pod klávesnice vylez ještě jeden termit jménem přetěžování operátorů.
Pro class vektor si můžu nedefinovat, jak vypadají operace odpovídající běžným operátorům, takže když hráč vyleze na žebřík, nastane hrac.poloha = hrac.poloha+zebrik.vektor.

Když už jsme u toho, ví tu někdo, proč se to menuje zrovna přetěžování?

PH

Od: ajtservis
tady je ten problem, ze za vsim vidim fyzicky kremik. tedy treba tu x51, 
kde je jasne dane, ze nic nez pamet, nebo nekolik typu pameti, v tom 
mikroradici neni :-). takze pokud vsechno je stejne jen misto v pameti, 
at pevne umistene a presne dlouhe nebo jen promena na chvili, tak proc 
to obalovat do tech "kouzel" ? to dela ten kompilator, vim, je to 
jednodussi, ale je to porad jen pamet a je to misto kde se da narazit. 
pamet by me treba nezajimala u matematickych operaci. tam bych to 
ulehceni ceckem bral, nez to resit po registrech a xx radcich pro kazdou 
pidi operaci. stacilo by mi vedet, ze xx registru/pameti je rezervovano 
pro matematiku nebo mam smulu.
no, uvidim jestli se to nejak poda :-)
diky vsem.
t.

Dne 31.03.2021 v 14:38 Pavel Brychta napsal(a):
> Dobře, takže ještě jinak:
> 
> V C vytvoříte globální proměnnou třeba:
> 
> int var;
> 
> při překladu pro ni překladač vytvoří místo v paměti a všechny odkazy v 
> programu namíří na tohle místo. Teď si ale představte, že nemáte jen 
> jednoduchou proměnnou, která zabírá paměť, ale chcete mít něco, co dělá 
> něco navíc - například si zapamatuje, kdy jste naposledy do té proměnné 
> něco psal. Nejde tedy o proměnnou, ale programový objekt, který má 
> nějaké vlastnosti - pojmenujme ten objekt (jeho třídu) timeStampInt. 
> Pokud takový objekt chcete používat, tak nestačí pro něj jen vyhradit 
> místo v paměti, ale je třeba také naplnit dodatečné parametry - v tomto 
> hypotetickém případě třeba nastavit časový okamžik posledního přístupu 
> jako -1 = nikdy nepřistoupeno. Tohle je právě úkol pro konstruktor 
> objektu, což z hlediska programování je jen procedura (abych se 
> přiblížil terminologii Pascalu), která zajistí to počáteční nastavení 
> časové značky a je volaná při vytváření objektu (vyhrazování paměťového 
> prostoru pro jeho data). Pokud tento objekt chcete vytvořit globálně, 
> syntaxe je jasná:
> 
> timeStampInt var;
> 
> potud je to správně, ale - protože víme, že při vytváření objektu je 
> nutné volat jeho konstruktor - je třeba si zde uvědomit, že to za nás 
> někdo musí udělat. Proto kompilátor při překladu sestavuje seznam takto 
> vytvořených objektů, který je použitý ve startup kódu pro volání 
> odpovídajících konstruktorů ještě předtím, než je řízení předáno Vašemu 
> programu, který píšete (main). Tím je zajištěné to, že takto vytvořené 
> objekty jsou inicializované a můžete je kdykoliv okamžitě začít používat.
> 
> Pavel Brychta
> 
> Dne 31. 03. 21 v 14:19 ajtservis napsal(a):
>> asi to mam nejak jinak. zadna tahle slova nepouzivam.
>> znam jen typy promenych, pak funkce a procedury a ostatni si naklikam 
>> na plochu v graficky podobe :-)
>> vrchol je mit zvlast data soubor pro ty nektere funkce a procedury a u 
>> exace soubor ini pro zapis a cteni ruznych parametru a vygenerovat 
>> html soubor jako protokol testu.
>> tohle dohromady klidne 20k radek programu a facha to(delphi 7).
>> asi tam ty tridy, objety atd. nekde budou, ale zatim jsem je zkoumat 
>> nepotreboval. srovnani vysledku sw, jeho funkce, pouzitelnosti a 
>> velikosti proti novym mladym objektovym programatorum, treba v c#, u 
>> nas ve firme, bylo vzdy plus pro me, tak fakt nevim :-)
>> jedinej "destruktor" jsem pak asi ja.
>> t.
>>
>>
>> Dne 31.03.2021 v 13:53 Pavel Brychta napsal(a):
>>> :D tak schválně zkusím tu větu zkrátit a věc popsat jinak:
>>>
>>> I v Delphi/Pascalu si jistě pamatujete na Constructor Init a 
>>> Destructor Done - při práci s objektem je ho potřeba nejdřív 
>>> "vytvořit" a pak taky občas "zrušit" - k tomuto účelu právě slouží 
>>> konstruktory a destruktory. Konstruktor je volaný ve chvíli, kdy se 
>>> objekt vytváří - v tomto případě, vzhledem k tomu, že objekt je 
>>> vytvořený staticky a globálně se konstruktor volá ve chvíli, kdy 
>>> probíhá inicializace všech statických/globálních objektů, tedy někde 
>>> ve startup kódu daného mikrokontroléru. Pořadí volání konstruktorů 
>>> určuje kompilátor, co se dělo předtím a co se bude dít potom určuje 
>>> struktura startup kódu. Nedokážu tedy říct v jakém stavu se zařízení 
>>> nachází - lidštěji co už nastavené je, co není a teprve se nastavovat 
>>> bude. V této situaci začnu nastavovat přerušovací systém a namířím ho 
>>> do jiné části kódu, která pracuje s proměnnými mimo aktuálně 
>>> inicializovaný objekt (v jakém jsou stavu bůh suď).
>>>
>>> No, nějak mi to nevyšlo na kratší popis, ale velmi rád se podívám, 
>>> jak to popsat snadněji ;-)
>>>
>>> Pavel Brychta
>>>
>>> Dne 31. 03. 21 v 13:37 ajtservis napsal(a):
>>>> hezky den.
>>>> sleduji tohle vlakno jako uplny "nececkar". zkusennost jen asm51 a 
>>>> delphi, ale neobjekovym zpusobem, bych rekl :-)
>>>> prvni vec co me prepadla je jak uz bylo uvedeno "Bohajeho, tohle že 
>>>> je pro děti?".
>>>> pak prispevek jak postupovat pomaleji, ten ok.
>>>> a nakonec to zabije veta, v dalsim prispevku "Například aktivace 
>>>> přerušovacího systému ve staticky volaném konstruktoru, kde je cíl 
>>>> volání mimo třídu je snad jasná hovadina pro jakýkoliv názor..." :-)
>>>> mam asi zasadni problem si pod slovy trida, metoda, objekt, 
>>>> konstruktor atd. predstavit o co v tom programovani vlastne jde ?
>>>> mam prakticky fumkcni projekty v asm nebo i deplhi/pascalu, ale 
>>>> vubec si je nedokazu v predstavach spojit s timto nazvoslovim, co 
>>>> cemu asi odpovida.
>>>> nekolik zacatku s lepsima ceckama a objektama, nekolik knizek, 
>>>> navodu a nic. proste se mi pri tech nazvech zablokuje mysleni a 
>>>> konec :-)
>>>> neni nejaka tabulka ekvivalent tech hruzonazvu, aby clovek treba 
>>>> nejak konvertoval ?
>>>> je ale videt , ze nekteri si v skladani dlouuuuhych vet z techto 
>>>> nazvu/zaklinadel libuji.
>>>> asi mam nejakou poruchu mysleni a ne ji porad prekonat :-)
>>>> te vyhuky pro deti, bych se asi i rad ucastnil, je to nekde dostupne 
>>>> jako stranky ?
>>>> tomik.
>>>> ps. treba bych byl dobry experimetalni objekt, jak udelat z hornika 
>>>> programatora :-)
>>>>
>>>>
>>>> Dne 31.03.2021 v 11:51 Jiří Nesvacil napsal(a):
>>>>> Dobrý den,
>>>>>
>>>>> jdete správnou cestou, ale ještě bych to zjednodušil. Před čase 
>>>>> jsem se ptal, zda nechte někdo nějaký on-line kroužek, ale ozval se 
>>>>> jen jeden, zda to děkuji, ale to je málo. Zatím jsme tedy sami 
>>>>> postoupili, ale dělám to jinak a mám následující fáce.
>>>>>
>>>>> a/ otevřít notepad a naučit aspoň napsat pár písmenek.
>>>>> b/ naučit se s myší a okopírovat kousek textu.
>>>>> c/ připravit kus kód, kde není nic v cizím jazyku, nejsou zde věci, 
>>>>> které se naučili nedávno. Začnu jen  s tím, aby se přahazoval řádek 
>>>>> v kódu. Něco jako jazyk "Karel" graficky. Jen přehodit pořadí, aby 
>>>>> se pochopila posloupnost.
>>>>> d/ další příklad volání metody s hodnotou třeba psun(5);
>>>>> e/... proměnné, cykly,... zase tímto jednoduchým stylem.
>>>>>
>>>>> ... objekty taky jednoduše. Neboli osobně bych vyházel všechny 
>>>>> define, založil to na malé třídě. Začít třeba se základem proměnné 
>>>>> v objektu tzv. instanční. Až následně do složitějších konstrukcí, 
>>>>> ale opět i složité konstrukce na jednoduchém příkladu tj. bez 
>>>>> ostatních věcí co se mohlo zapomenout.... . Je to o tom to dělat 
>>>>> pomalu. Možná máte větší děti nebo toho znají více... .
>>>>>
>>>>> Jirka
>>>>>
>>>>>
>>>>> Dne 30.03.2021 v 20:08 Pavel Hudecek napsal(a):
>>>>>>
>>>>>> Dobrý den všem,
>>>>>>
>>>>>> Udělal jsem malou ukázku programu v C++ pro děti na kroužek, 
>>>>>> prosím o zhodnocení, zda v tom nejsou nějaký nevhodný věci:-)
>>>>>>
>>>>>> (celé je to pro Xnano416 mající 1 LED a 1 tlačítko)
>>>>>>
>>>>>> Otázka je, jak se to zmrší posláním v mailu…
>>>>>>
>>>>>> #include <avr/io.h>
>>>>>>
>>>>>> #include <avr/interrupt.h>
>>>>>>
>>>>>> #define F_CPU (20000000UL/6UL)
>>>>>>
>>>>>> #define LED_bit                               5 // LEDka
>>>>>>
>>>>>> #define TL_bit                  4 // tlačítko
>>>>>>
>>>>>> #define TEST_bit             3 // test přerušení osciloskopem
>>>>>>
>>>>>> #define TEST_bit2           2 // test čekání osciloskopem
>>>>>>
>>>>>> #define TL_jeStisk          ((PORTB.IN & (1<<TL_bit)) == 0)
>>>>>>
>>>>>> volatile unsigned int       ms=0;
>>>>>>
>>>>>> volatile unsigned char    msSync=0;
>>>>>>
>>>>>> void cekej(unsigned int n); // prototyp funkce - jen aby za ním 
>>>>>> bylo vidět jak funkce vypadá
>>>>>>
>>>>>> class clTlac { // 
>>>>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>
>>>>>> public:
>>>>>>
>>>>>>                 clTlac() { // konstruktor - spusti se pri 
>>>>>> vytvoreni objektu ----------------------------
>>>>>>
>>>>>> PORTB.PIN4CTRL = PORT_PULLUPEN_bm;
>>>>>>
>>>>>>                                // zapnout pull-up pro tlačítko
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 void cek() { // cekani na stisk 
>>>>>> --------------------------------------------------------
>>>>>>
>>>>>> while(TL_jeStisk) cekej(0);
>>>>>>
>>>>>> while(!TL_jeStisk) cekej(0);
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 void stisk(); // udalost stisku tlacitka - jen 
>>>>>> deklarace
>>>>>>
>>>>>>                 bool stav=false;
>>>>>>
>>>>>> };
>>>>>>
>>>>>> class clLED { // 
>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>
>>>>>>                 friend void cekej(unsigned int n);
>>>>>>
>>>>>>                 // friend smí i do private
>>>>>>
>>>>>> public:
>>>>>>
>>>>>>                 const unsigned int PMAX = F_CPU / 1000UL;
>>>>>>
>>>>>>                 const unsigned int P1 = PMAX / 100;
>>>>>>
>>>>>>                 clLED() { // konstruktor - spusti se pri vytvoreni 
>>>>>> objektu -----------------------------
>>>>>>
>>>>>>                                PORTB.OUTSET = 1<<LED_bit; // 
>>>>>> nastavit na 1, aby LEDka nesvítila od začátku
>>>>>>
>>>>>>                                PORTB.DIR = (1<<LED_bit) | 
>>>>>> (1<<TEST_bit) | (1<<TEST_bit2) ; // zapnout výstupy pro LED
>>>>>>
>>>>>> PORTB.PIN5CTRL = PORT_INVEN_bm; // Invertovat, aby LED svitila pri 
>>>>>> 1 (1 v datech)
>>>>>>
>>>>>> PORTMUX_CTRLC = PORTMUX_TCA02_ALTERNATE_gc;
>>>>>>
>>>>>> TCA0_SINGLE_CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc;
>>>>>>
>>>>>> TCA0_SINGLE_CTRLB = TCA_SINGLE_CMP2EN_bm | 
>>>>>> TCA_SINGLE_WGMODE_SINGLESLOPE_gc;
>>>>>>
>>>>>> TCA0_SINGLE_CTRLC = 0;
>>>>>>
>>>>>> TCA0_SINGLE_CTRLD = 0;
>>>>>>
>>>>>> TCA0_SINGLE_PER = F_CPU / 1000UL;
>>>>>>
>>>>>> TCA0_SINGLE_INTCTRL = TCA_SINGLE_OVF_bm;
>>>>>>
>>>>>> TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm;
>>>>>>
>>>>>> TCA0_SINGLE_CMP2 = P1;
>>>>>>
>>>>>> TCA0_SINGLE_CTRLA |= TCA_SINGLE_ENABLE_bm;
>>>>>>
>>>>>> __asm__("sei");
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 void svitit(uint8_t proc) { // rozsvitit na zadane 
>>>>>> % -----------------------------------
>>>>>>
>>>>>> TCA0_SINGLE_CMP2 = P1 * proc;
>>>>>>
>>>>>>                                tim = 0;
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 void blikat(unsigned int t, unsigned char h, 
>>>>>> unsigned char l) { // ---------------------
>>>>>>
>>>>>>                                tim  = t;
>>>>>>
>>>>>>                                cnt  = 0;
>>>>>>
>>>>>>                                pwmH = P1 * h;
>>>>>>
>>>>>>                                pwmL = P1 * l;
>>>>>>
>>>>>> TCA0_SINGLE_CMP2 = pwmH;
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 unsigned int procToPWM(unsigned char n) { // 
>>>>>> prevod procent na PWM ---------------------
>>>>>>
>>>>>>                                return P1 * n;
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>> private:
>>>>>>
>>>>>>                 unsigned int pwmL = 0, pwmH = PMAX, tim  = 0, cnt 
>>>>>> = 0;
>>>>>>
>>>>>>                 void togglePwm() { // prehodit PWM z low na hi / 
>>>>>> naopak --------------------------------
>>>>>>
>>>>>>                                if (TCA0_SINGLE_CMP2 == pwmH)
>>>>>>
>>>>>> TCA0_SINGLE_CMP2 = pwmL;
>>>>>>
>>>>>>                                else
>>>>>>
>>>>>> TCA0_SINGLE_CMP2 = pwmH;
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>> };
>>>>>>
>>>>>> // Tady se podle tříd clTlac a clLED vytvoří objekty Tlacitko a 
>>>>>> Led. To spustí jejich konstruktory.
>>>>>>
>>>>>> clTlac     Tlacitko;
>>>>>>
>>>>>> clLED     Led;
>>>>>>
>>>>>> void cekej(unsigned int n) { // 
>>>>>> ==============================================
>>>>>>
>>>>>>                 static bool tlacStickPred=false;
>>>>>>
>>>>>>                 __asm__("cli");
>>>>>>
>>>>>>                 ms=0;
>>>>>>
>>>>>>                 __asm__("sei");
>>>>>>
>>>>>>                 while(1) {
>>>>>>
>>>>>>                                PORTB.OUTTGL = (1<<TEST_bit2);
>>>>>>
>>>>>>                                if (msSync==1) { // 
>>>>>> ----------------------------------------
>>>>>>
>>>>>> msSync=0;
>>>>>>
>>>>>> Tlacitko.stav = TL_jeStisk;
>>>>>>
>>>>>> if (Led.tim>0) { // je zapnute blikani
>>>>>>
>>>>>> if (++Led.cnt>Led.tim) {
>>>>>>
>>>>>> Led.cnt=0;
>>>>>>
>>>>>> Led.togglePwm();
>>>>>>
>>>>>> }
>>>>>>
>>>>>> }
>>>>>>
>>>>>>                                } // if (msSync==1)
>>>>>>
>>>>>>                                if (!tlacStickPred && 
>>>>>> Tlacitko.stav) { // právě bylo stisknuto, vyvolat událost
>>>>>>
>>>>>> Tlacitko.stisk();
>>>>>>
>>>>>>                                }
>>>>>>
>>>>>> tlacStickPred=Tlacitko.stav;
>>>>>>
>>>>>> __asm__("cli");
>>>>>>
>>>>>>                                if (ms>=n) break;
>>>>>>
>>>>>> __asm__("sei");
>>>>>>
>>>>>>                 } // while(1)
>>>>>>
>>>>>>                 __asm__("sei");
>>>>>>
>>>>>> }
>>>>>>
>>>>>> // implementace obsluhy události stisk tlačítka
>>>>>>
>>>>>> void clTlac::stisk() { // 
>>>>>> ===================================================
>>>>>>
>>>>>>                 static bool b=false;
>>>>>>
>>>>>>                 // zatímco v mainu se čekat musí, tady se naopak 
>>>>>> nesmí
>>>>>>
>>>>>>                 if (b) {
>>>>>>
>>>>>> Led.blikat(200, 100, 0);
>>>>>>
>>>>>>                 } else {
>>>>>>
>>>>>> Led.blikat(200, 60, 30);
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>>                 b = !b;
>>>>>>
>>>>>> }
>>>>>>
>>>>>> int main(void) { // 
>>>>>> ###########################################################
>>>>>>
>>>>>>                 // tady nic neni: inicializace je v konstruktorech
>>>>>>
>>>>>>                 Led.blikat(100, 70, 20);
>>>>>>
>>>>>>                 while (1) { // 
>>>>>> ---------------------------------------------------
>>>>>>
>>>>>>                                // je jedno co tu je, hlavně že to 
>>>>>> obsahuje čekání
>>>>>>
>>>>>>                                cekej(100);
>>>>>>
>>>>>> Tlacitko.cek();
>>>>>>
>>>>>>                 }
>>>>>>
>>>>>> }
>>>>>>
>>>>>> ISR (TCA0_OVF_vect) { // 
>>>>>> =====================================================
>>>>>>
>>>>>>                 PORTB.OUTTGL = (1<<TEST_bit);
>>>>>>
>>>>>>                 ms++;
>>>>>>
>>>>>>                 msSync=1;
>>>>>>
>>>>>>                 TCA0_SINGLE_INTFLAGS = TCA_SINGLE_OVF_bm;
>>>>>>
>>>>>> }

------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20210331/a2ebadb9/attachment-0001.html>


Další informace o konferenci Hw-list