Close

Objektově orientované programování I. – Úvod

Programovací jazyky - Wordcloud - Zdroj Wikipedia Commons

V prvním článku ze seriálu věnovanému programování obecně jsme si popsali různé typy programovacích jazyků a ukázali jsme si, jak přibližně vypadají programy v nich napsané. Také jsme došli k tomu, že C++, ve kterém se běžně Arduino programuje, je objektově orientovaný jazyk. A právě objektově orientovaným programováním se dnes budeme zabývat.


Některé z vás jsem teď možná zmátl. Tvrdím, že Arduino se běžně programuje v C++. V předchozích článcích jsem ale tvrdil, že Arduino programujeme v jazyce Wiring. Skutečnost je taková, že Wiring je knihovna pro jazyk C++, která zjednodušuje programování Arduina. Jelikož běžný uživatel Arduina většinou neví, jaká konstrukce pochází z C++ a jaká je specifická pro Wiring, ujalo se v Arduino komunitě pojmenování jazyk Wiring. To je sice z technologického hlediska nesprávné označení, ale pro naše účely není nutné mezi C++ a Wiring přesně rozlišovat.

Objektově orientované programování

Základním prvkem objektově orientovaných (dále OO) jazyků je objekt. Objekt si můžeme představit jako konkrétní věc – například psa Alíka. Abychom mohli takovéto objekty vytvářet, potřebujeme nějaký vzor – řekněme vzor, který si nazveme pes. Takovému vzoru se v OO programování říká třída. Ta nám definuje vlastnosti (atributy) a schopnosti (metody) objektu. Podle třídy pes je možné vytvořit libovolné množství psů – psa Alíka, psa Žeryka, psa Punťu… Těmto konkrétním objektům se říká také instance třídy pes. Jak by mohla vypadat třída pes? Třeba takto:

class Pes{
   private: 
       String jmeno = "";
       int vyska = 0;
   public: 
       Pes(String, int);
       void stekej();
}; //tady opravdu musí být středník!

Odbočka do terminologie. Funkcím, které náleží objektu se říká metody. Proměnným, které náleží objektu se říká atributy.

Máme tedy objekt pes, který má atributy jmenovyska a umí štěkat pomocí metody stekej. Všimněte si, že jmeno a vyska jsou uvozené klíčovým slovem private. Tyto proměnné jsou označeny za „soukromé“. Bude k nim možné přistupovat pouze uvnitř metod objektu. Naopak klíčové slovo public označuje atributy a metody, které jsou dostupné i vně objektu – tedy je možné je volat v rámci programu. Metoda Pes() (která má stejný název, jako objekt samotný) je speciální a říká se jí konstruktor. Pomocí konstruktoru dochází k vytváření nových instancí třídy Pes. V rámci konstruktoru můžeme například nastavit hodnoty privátních atributů podle parametrů konstruktoru a podobně. Konstruktor se definuje takto:

Pes::Pes(String jm, int vy){
   jmeno = jm; 
   vyska = vy;
}

Atributy vytvořené instance třídy Pes se nastaví na zadané hodnoty. Ještě nám zbývá vytvořit metodu stekej.

void Pes::stekej(){
   Serial.print(jmeno);
   Serial.print(" steka ");
   Serial.println("Haf!");   
}

Nyní tedy máme šablonu, podle které můžeme vytvořit různé konkrétní psy.

Pes alik("Alik", 100); //pes Alik vysoký 100cm
Pes zeryk("Zeryk", 60); //pes Zeryk vysoký 60cm

A ještě zbývá psy trochu popíchnout, aby zaštěkali.

alik.stekej();
zeryk.stekej();

Celý program, který nechá psy zaštěkat, tedy vypadá následovně:

class Pes{
   private: 
       String jmeno = "";
       int vyska = 0;
   public: 
       Pes(String, int);
       void stekej();
}; //tady opravdu musí být středník!
Pes::Pes(String jm, int vy){
   jmeno = jm; 
   vyska = vy;
}
void Pes::stekej(){
   Serial.print(jmeno);
   Serial.print(" steka ");
   Serial.println("Haf!");   
}
Pes alik("Alik", 100);
Pes zeryk("Zeryk", 60);
void setup() {
   Serial.begin(9600);
   Serial.println("Smecka");
   alik.stekej();
   zeryk.stekej();
}
void loop() {
}

Praktický příklad

Možná si říkáte, že je sice hezké, že máme vytvořenou třídu Pes, ale k čemu nám je u Arduina platná? Ukažme si tedy nějaký jednoduchý praktický příklad.

class LED{
   private: 
       int pin;
       boolean stav = LOW; //výchozí stav LED je vypnuto
       void nastav(boolean);
   public: 
       LED(int);
       void zapni();
       void vypni();
       void prepni();
       boolean vratStav();
};
LED::LED(int p){
   pin = p;
   pinMode(pin, OUTPUT);
   digitalWrite(pin, stav);
}
void LED::zapni(){
   nastav(HIGH);
}
void LED::vypni(){
   nastav(LOW);    
}
void LED::prepni(){
   nastav(!stav); //nastaví LED na obrácenou hodnotu (0->1, 1->0)
}
void LED::nastav(boolean s){
   stav = s;
   Serial.print("Nastavuji ");
   Serial.print(stav);
   Serial.print(" na pinu ");
   Serial.println(pin);
   digitalWrite(pin, stav);
}
boolean LED::vratStav(){
   return stav;     
}
LED L13(13);
void setup() {
   Serial.begin(9600);
   L13.zapni();
   delay(1000);
   L13.vypni();
   delay(1000);
   for(int i = 0; i <= 10; i++){
       L13.prepni();
       delay(500);    
   }
   Serial.print("Led zustala ve stavu ");
   Serial.println(L13.vratStav());
}
void loop() {
}

Jedná se o velice jednoduchou třídu sloužící k ovládání LED diody. Její public metody jsou zapni, vypni, prepni a vratStav (jejich název je snad dostatečně popisný 🙂 ).  Všimněte si, že třída LED obsahuje i private metodu nastav, která slouží k  nastavení stavu LED a zároveň k výpisu stavu na sériovou linku. Metoda nastav je volána uvnitř jiných metod třídy LED. Také je zde předvedena technika, která se používá k získání hodnot privátních atributů objektů. Přímo k atributu stav bychom se totiž pomocí L13.stav nedostali, proto musíme využít nějakou public metodu.

To byl letmý úvod do OO programování. O jeho dalších principech více zase příště.

Zbyšek Voda

Zbyšek Voda

Už nějaký čas se zajímám o věci kolem Internetu věcí a otevřeného hardware a software. Tak jsem se také v roce 2010 dostal k Arduinu, pro které dodnes programuji a taky píšu články o práci s ním. Baví mě vymýšlet, jak staré věci používat novým způsobem.
Zbyšek Voda

12 Comments on “Objektově orientované programování I. – Úvod

BorgMcz
20.6.2016 at 21:03

Já bych se dovolil zeptat, na jednu věc, která by mohla být dnešnímu tématu blízká.
Potřeboval bych v jednom projektu v následujícím kódu měnit v posloupnosti jméno :
RBD::Button jméno (pin);
toto je základní vytvoření funkce, mohu ji tvořit ručně ale protože kód bude složitější a bude se mnohokrát opakovat a tak hledám jak jinak na to: ručně to udělám takto:

RBD::Button jmeno0 (30);
RBD::Button jmeno1 (31);
RBD::Button jmeno2 (32);
ale potřeboval bych to tvořit automaticky za pomoci cyklu, něco jako asi takhle:

for (int x=0; x<15; x++) {
RBD::Button jmeno(x) (y);
}
nevím, jak správně to zapsat, aby IDE pochopilo co chci. Dá se to nějak zapsat?
Jde mi pouze o to jméno plus číslo v X , Y je jasné.

Zbyšek Voda
Zbyšek Voda
20.6.2016 at 21:13

Dobrý den. Toto budu probírat v jednom z dalších článků. Zatím vas nasměruji, kde hledat – podívejte se, jak se vytváří v C++ pole objektů a uložte si jednotlivá tlačítka do pole 🙂

BorgMcz
21.6.2016 at 6:19

To jsem zkoušel, zjevně ale nesprávným zápisem. U toho Y kde dosazuji přiřazené piny (tedy jen čísla) mi to funguje, ale ne pro ten název. Nemohl bych poprosit o pomoc třeba na mailu? mm.svet(zavi.nač)centrum.cz
Diky.

Zbyšek Voda
Zbyšek Voda
21.6.2016 at 13:06
BorgMcz
21.6.2016 at 21:10

Rekl bych, že ted v tom mam jeste vetsi zmatek nez predtim :-)) Mohl bych poprosit o kontakt pres mail?

Zbyšek Voda
Zbyšek Voda
22.6.2016 at 8:28
tribal.cz
20.6.2016 at 16:49

Zbyšku nádhera, ale nemohu se ubránit dojmům jako překvapení a zmatenost. Jak dlouho lze arduino programovat pomocí OOP? Jedná se o funkci přidanou někdy v poslední době? ani ne před půl rokem jsem se o to zajímal na jednom fóru (pravda nikdy jsem to nezkusil), a odpovědí mi byl imaginární výsměch nejméně tří až čtyř členů daného fóra. Prakticky mi bylo řečeno že pokud chci programovat objektově mám zapomenout na arduino a vrátit se k vyšším jazykům.

Zbyšek Voda
Zbyšek Voda
21.6.2016 at 10:33

Dobrý den, nerad bych plácnul nějakou blbost, ale myslím, že Arduino toto podporuje od začátku – knihovna Wiring je na C++, které objekty přímo podporuje. C++ nakonec stejně skončí v podobě nul a jedniček, takže nevidím důvod, proč by to nemělo jít 🙂

Objekty jsou většinou dostupné v knihovnách pro obsluhu všeho možného (ethernnet, motory, senzory…), takže se uživatel většinou s definováním objektů nesetká, ale jen je používá.

Melas
19.6.2016 at 20:06

Zábavnou formou vysvětlená problematika. Je pravda, že jsou funkce, které používám, ale ve skutečnosti jim nerozumím a tohle mi je osvětluje. Děkuji.

posjirka
19.6.2016 at 11:03

Zbyšku …. tleskám. Takhle hezky vysvětlení tříd a metod jsem nikde jinde neviděl.
Fakt super.

Zbyšek Voda
Zbyšek Voda
20.6.2016 at 15:06

Děkuji. To bylo cílem, tak jsem rád, že se mi to snad i povedlo 🙂

Tomáš
19.6.2016 at 10:48

Napsat komentář