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 je konkrétní věc – například pes Alík. 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 – parametry a schopnosti – metody objektu. Podle třídy pes je možné vytvořit libovolné množství psů – pes Alík, pes Žeryk, pes Punťa… 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žejí objektu se říká metody.
Máme tedy objekt pes, který má parametry jmeno a vyska a umí štěkat pomocí metody stekej. Všimněte si, že jmeno a vyska jsou uvozené návěštím private. Tyto proměnné jsou označeny za „soukromé“. Bude k nim možné přistupovat pouze uvnitř metod objektu. Naopak návěští public označuje parametry 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 parametrů podle parametrů konstruktoru a podobně. Konstruktor se definuje takto:
Pes::Pes(String jm, int vy){ jmeno = jm; vyska = vy; }
Parametry 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 parametrů objektů. Přímo k parametru 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ě.