Chci geek triko! Chci geek triko!
Extra 10 % bodů navíc a tričko zdarma při zadání kódu "TRIKO10"

Lekce 2 - První objektová aplikace v C++

C a C++ C++ Objektově orientované programování První objektová aplikace v C++

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Na začátku kurzu se základními strukturami jazyka C++ jsme si vytvořili program Hello world. Udělejme si nyní podobný program jako úvod do objektově orientovaného programování. Naprogramujme si Hello object world!

Vytvoření projektu

Nejprve si vytvoříme nový projekt (konzolovou aplikaci). Postup vytvoření projektu můžete vidět na screenshotech níže.

Vytvoření projektu v C++

Projekt založíme jako klasickou konzolovou aplikaci.

Specifikace projektu v C++

Následně klikneme na Next a nastavíme projekt podle následujícího obrázku a klikneme na Finish.

Vlastnosti projektu

V projektu si vytvoříme nový soubor main.cpp, což uděláme kliknutím pravým tlačítkem na projekt v Solution Exploreru -> Add -> New Item.

Přidání souboru do projektu

Následně vybereme .cpp soubor.

Typ souboru

Do tohoto souboru vložíme základní strukturu aplikace v C++ jako jsme byli zvyklí doposud:

#include <iostream>

using namespace std;

int main()
{
    return 0;
}

V Solution Exploreru klikneme pravým tlačítkem myši na složku Source files a vybereme Add -> Class.

Přidání třídy v C++ projektu

V okně, které se nám zobrazí, rozklikneme C++ Class. Pak se zobrazí další okno, ve kterém vyplníme údaje podle obrázku. Jde o zadání názvu souborů třídy, která bude reprezentovat vzor pro objekt, který umí pozdravit:

Nastavení vlastností třídě v C++

Visual studio nám vytvoří dva soubory: Zdravic.h (tam bude samotná třída) a Zdravic.cpp (kde budou definice funkcí). Rozdělení třídy do těchto dvou souborů je nutné - viz lekce o kompilaci v C a C++. Obsah souborů přepíšeme do následující podoby:

Zdravic.h

#ifndef __ZDRAVIC_H__
#define __ZDRAVIC_H__

class Zdravic
{

};

#endif

Zdravic.cpp

#include "Zdravic.h"

Preprocesové direktivy (#ifndef, #define a #endif) zajišťují, že bude soubor includován jen jednou. Visual Studio ve výchozím nastavení používá #pragma once direktivu, ale námi ukázaná je praktičtější (funguje i při kompilaci na Linuxech). Původně vygenerované funkce Zdravic(void) a ~Zdravic(void) byly tzv. konstruktor a destruktor, na které se podíváme až v příští lekci.

Deklarace metody

Až budeme tuto třídu používat, budeme chtít, aby něco uměla. Kvůli tomu si třídu Zdravic rozšíříme o nějakou metodu. Ta se v C++ zapisuje stejně jako funkce:

Zdravic.h

#ifndef __ZDRAVIC_H__
#define __ZDRAVIC_H__

class Zdravic
{
public:
    void pozdrav();
};

#endif

Zdravic.cpp

#include <iostream>
#include "Zdravic.h"

using namespace std;

void Zdravic::pozdrav(void)
{
    cout << "Hello object world!";
}

Metodu musíme deklarovat 2x, jednou jako hlavičku do .h souboru a jednou i s tělem do .cpp souboru. Zde jsme prozatím skončili, přejdeme do main.cpp.

Vytvoření instance třídy

Nyní si v těle metody main() vytvoříme instanci třídy Zdravic. Nejdříve ale musíme říct, že chceme používat naši třídu Zdravic, kterou jsme si před chvílí vytvořili. To provedeme naincludováním naší třídy do souboru main.cpp pomocí #include "Zdravic.h". Na rozdíl od klasických includů (například iostream) si můžete všimnout nahrazení ostrých závorek za uvozovky. Pokud použijeme hranaté závorky, kompilátor hledá soubor ve svých cestách (zpravidla cesty ke knihovnám). Pokud použijeme uvozovky, kompilátor použije relativní cestu (v našem případě aktuální projekt).

Objekty se ukládají do proměnných, název třídy slouží jako datový typ (jak je tomu například u int), instance můžeme pojmenovat jakkoliv. Deklarujme si proměnnou a následně v ní založme novou instanci třídy Zdravic:

#include <iostream>
#include "Zdravic.h"

using namespace std;

int main()
{
    Zdravic _zdravic;
    return 0;
}

Tím se vytvoří proměnná _zdravic. Instanci můžeme vytvořit i takto:

Zdravic* _zdravic = new Zdravic();

Tento způsob vytvoří instanci dynamicky na haldě. Vrátíme se k němu v pokročilejších dílech našeho C++ kurzu.

Volání metody

A protože již máme vytvořený svůj první objekt (instanci), můžeme zavolat jeho metodu. Na konec kódu (před return 0;) ještě doplníme cin.get() (aby program hned neskončil a čekal na stisk libovolné klávesy). Soubor main.cpp vypadá ve finále takto:

main.cpp

#include <iostream>
#include "Zdravic.h"

using namespace std;

int main()
{
    Zdravic _zdravic;
    _zdravic.pozdrav();
    cin.get();
    return 0;
}

Teď můžeme program spustit. Výstup bude následující:

Konzolová aplikace
Hello object world!

Máme tedy svou první objektovou aplikaci! Logiku provádí příslušný objekt. Až budeme psát větší aplikace, rozdělení funkcí do jednotlivých objektů velmi oceníme kvůli přehlednosti.

Parametry metody

Dejme nyní naší metodě pozdrav() parametr jmeno, aby dokázala pozdravit konkrétního uživatele:

Zdravic.h

#ifndef __ZDRAVIC_H__
#define __ZDRAVIC_H__
#include <string>

using namespace std;

class Zdravic
{
public:
    void pozdrav(string jmeno);
};

#endif

Zdravic.cpp

#include <iostream>
#include "Zdravic.h"

using namespace std;

void Zdravic::pozdrav(string jmeno)
{
    cout << "Ahoj uzivateli " << jmeno << endl;
}

Nyní upravíme naši funkci main():

Zdravic _zdravic;
_zdravic.pozdrav("Karel");
_zdravic.pozdrav("Petr");

A po spuštění aplikace získáme následující výstup:

Konzolová aplikace
Ahoj uzivateli Karel
Ahoj uzivateli Petr

Atributy třídy

Třídě nyní přidáme nějaká data ("proměnnou"), kde bude uložen text pozdravu. Z minulé lekce již víme, že třídy obsahují funkcionalitu a data. Funkci již máme, ukažme si tedy jak se do objektů ukládají data. Datové složky třídy (atributy) se definují stejně jako proměnné. Upravme tedy naši třídu:

Zdravic.h

Atribut (proměnnou) deklarujeme v hlavičkovém souboru:

class Zdravic
{
public:
    string text;
    void pozdrav(string jmeno);
};

Nyní si všechny instance třídy Zdravic ukládají svůj text.

Zdravic.cpp

Upravme metodu pozdrav() tak, aby ke zdravení používala text v atributu text:

void Zdravic::pozdrav(string jmeno)
{
    cout << text << " " << jmeno << endl;
}

main.cpp

Text nyní musíme prvně nastavit vytvořené instanci v main.cpp:

Zdravic _zdravic;
_zdravic.text = "Ahoj uzivateli";
_zdravic.pozdrav("Karel");
_zdravic.pozdrav("Petr");
_zdravic.text = "Vitam te tu programatore";
_zdravic.pozdrav("Richard");

A výstup aplikace:

Konzolová aplikace
Ahoj uzivateli Karel
Ahoj uzivateli Petr
Vitam te tu programatore Richard

Návratová hodnota metody

Vzhledem k objektovému návrhu není nejvhodnější, aby každý objekt ovlivňoval vstup a výstup. Pochopitelně narážím na naše vypisování do konzole. Každý objekt by měl mít určitou kompetenci (odpovědnost) a tu by neměl překračovat. Pověřme náš objekt pouze sestavením pozdravu a jeho výpis si zpracujeme někde jinde, v našem případě v metodě main(). Výhodou takto navrženého objektu je vysoká univerzálnost a znovupoužitelnost. Objekt doposud umí jen psát do konzole, my ho však přizpůsobíme tak, aby daná metoda text pouze vracela a bylo na jeho příjemci, jak s ním naloží. Takto můžeme pozdravy ukládat do souborů, vypsat na formulář nebo dále zpracovávat.

Jelikož chceme, aby metoda vracela hodnotu typu string, změníme její dosavadní typ void na string. K návratu hodnoty použijeme příkaz return. Upravme kód třídy:

Zdravic.h

class Zdravic
{
public:
    string text;
    string pozdrav(string jmeno);
};

Zdravic.cpp

A stejně tak i implementaci:

string Zdravic::pozdrav(string jmeno)
{
    return text + " " + jmeno + "!\n";
}

main.cpp

K tomu musíme upravit soubor main.cpp:

int main()
{
    Zdravic _zdravic;
    _zdravic.text = "Ahoj uzivateli";
    cout << _zdravic.pozdrav("Karel");
    cout << _zdravic.pozdrav("Petr");
    _zdravic.text = "Vitam te tu programatore";
    cout << _zdravic.pozdrav("Richard");
    cin.get();
    return 0;
}

Nyní je náš kód dle dobrých praktik. Zdrojové kódy jsou přiloženy pod článkem. Celý program si můžete vyzkoušet zde nebo v přiloženém projektu.

#include <iostream>
#include "zdravic.h"
using namespace std;

int main()
{
    zdravic _zdravic;
    _zdravic.text = "Ahoj uzivateli";
    cout << _zdravic.pozdrav("Karel");
    cout << _zdravic.pozdrav("Petr");
    _zdravic.text = "Vitam te tu programatore";
    cout << _zdravic.pozdrav("Richard");
    cin.get();
    return 0;
}
#include <iostream>
#include "zdravic.h"

using namespace std;

string zdravic::pozdrav(string jmeno)
{
    return text + " " + jmeno + "!\n";
}
#ifndef __ZDRAVIC_H__
#define __ZDRAVIC_H__
#include <string>
using namespace std;

class zdravic
{
    public:
        string text;
        string pozdrav(string jmeno);
};

#endif

A jsme u konce. Námi napsaný program má již nějakou úroveň, i když vlastně nic nedělá. Za úkol máte předělat si naši konzolovou kalkulačku do objektů. Příště, Hrací kostka v C++ a konstruktory, se blíže podíváme na slíbené konstruktory a destruktory.


 

Stáhnout

Staženo 49x (4.66 kB)
Aplikace je včetně zdrojových kódů v jazyce C++

 

 

Článek pro vás napsal patrik.valkovic
Avatar
Jak se ti líbí článek?
5 hlasů
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity (7)

 

 

Komentáře

Avatar
Petr Svobodník:1.11.2017 20:09

Proč bylo potřeba tvořit nový soubor main.cpp, když VS vytvořilo samo nazevprojektu.cpp? Nefungovalo mi to tak...

 
Odpovědět 1.11.2017 20:09
Avatar
Martin Petrovaj
Překladatel
Avatar
Martin Petrovaj:1. ledna 0:26

Dobrý, je to trochu "mimo mísu" a nie som si istý, či to nebude niekde ďalej spomenuté, ale niekde som počul, že vraj v hlavičkových súboroch by sa nikdy nemali používať žiadne using (teda čakal by som v ukážkach header súborov std::string a pod.).

V C++ ale len začínam tak si nie som 100% istý, čo nepredstaviteľne strašné sa v takomto prípade stane. Mohli by ste mi vysvetliť, čo tým mohlo byť myslené a ako to má byť správne? Ďakujem

Odpovědět 1. ledna 0:26
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Martin Petrovaj
patrik.valkovic:1. ledna 18:44

Problém je v tom, že když se hlavičkový soubor někde includuje, tak se using použije i v tomto souboru.
Vyloženě pravidlo to není, spíše jde o konvenci.

Odpovědět  +1 1. ledna 18:44
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Osuský
Člen
Avatar
Jan Osuský:29. ledna 17:34

Dobrý den,
Mám přístup i k jiné literatuře, která je ovšem staršího data vydání. V této literatuře se uvádí příklad vytvoření tříd bez vytváření souborů typu zdravic.cpp a zdravic.h které generovalo VS a celý kod se vkládá do jednoho souboru. Mohl byste mi někdo vysvětlit rozdíl mezi těmito metodami vytvoření tříd? A připadně uvést jak převádět mnou uvedený způsob na způsob, který poskytuje VS.
Děkuji vám za případné odpovědi.

 
Odpovědět 29. ledna 17:34
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Jan Osuský
patrik.valkovic:29. ledna 18:27

Zdravím,
odkáži vás na díl o kompilaci: https://www.itnetwork.cz/…-a-cplusplus
ačkoliv se jedná o C, v C++ to funguje naprosto stejně. Snažil jsem se v tomto díle (popřípadě v tom dalším) popsat, proč je důležité program rozdělit na hlavičkový soubor a implementační soubor. Pokud by byly ještě nějaké dotazy, rád je zodpovím.

Odpovědět 29. ledna 18:27
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Osuský
Člen
Avatar
Jan Osuský:30. ledna 17:25

Děkuji vám za radu, hlavně v tom druhém článku to bylo dobře vysvětleno :)

 
Odpovědět 30. ledna 17:25
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.