Retezec krok 5 - Zlepšení třídy Retezec

V tomto kroku se dozvíte něco o kopírovacím konstruktoru, přetěžování operátorů a něco málo i o friend funkcích a o ukazateli this.

Nejprve přidáme ještě jeden konstruktor. Vzpomeňte si, že konstruktor je funkce, která má stejné jméno jako její třída a je volána pokaždé když vzniká nový objekt dané třídy. Naše třída řetězec má zatím 2 konstruktory. Jeden nebere žádné parametry a slouží pro vytvoření prázdného řetězce. Druhý konstruktor bere jako parametr ukazatel na char, tedy textový řetězec a umožňuje vytvořit objekt třídy Retezec, který už obsahuje nějaký text. Teď přidáme třetí konstuktor, který bude jako parametr požadovat referenci na již existující objekt třídy Retezec. Tuším, že takovému konstruktoru se říká kopírovací a hodí se pro kopírování jednoho řetězce do druhého.

Otevřete soubor RETEZ.H a pod deklaraci druhého konsturktoru Retezec(char* text); přidejte následující řádek:

Retezec(const Retezec& retez); //deklarace třetího konstruktoru

Do souboru RETEZ.CPP přidejte definici těla třetího konstruktoru

Retezec::Retezec(const Retezec& ret)
{
strcpy(m_text, ret.m_text);
m_delka = ret.m_delka;
}

Dále budeme často potřebovat přistupovat přímo k jednotlivým znakům řetězce, proto přidáme členské funkce GetAt a SetAt. GetAt(int pos) bude vracet znak na pozici určené parametrem pos a SetAt(int pos,char zn) naopak nastaví znak zn na pozici pos.

Otevřete soubor RETEZ.H a do public části pod deklarace konstruktorů přidejte toto:

char GetAt(int pos) { assert(pos < m_delka); return m_text[pos]; };
void SetAt(int pos,char zn) { assert(pos < m_delka); m_text[pos] = zn; };

Obě funkce jsou jednoduché a proto jsme je definovaly jako inline přímo v souboru RETEZ.H.
Všimněte si makra assert, Toto makro vyhodnocuje předaný výraz a pokud není pravdivý, zastaví program a vypíše na monitor podobné hlášení: "Assertion failed [soubor] [řádek] ". Zde slouží k ověření, že žádaný znak skutečně patří do řetězce u funkce GetAt() a k ověření že vkládáme znak na platnou pozici řetězce u SetAt(). Makro může být z výsledného programu
po odladění odstraněno vložením direktivy #define NDEBUG před #include <assert.h>.

Vložte řádek

#include <assert.h>

na začátek souboru RETEZ.H. Inklůdování souborů do *.H sice není nejšťastnější, ale momentálně se mi nechce vymýšlet nějaké finty.

Další užitečnou věcí bude, když půjde spojovat řetězce pomocí operátoru +, takže budete moci napsat např.
retez3 = retez1 + " Ahoj " + retez2; kde retez1 až 3 jsou objekty naší třídy Retezec.
K tomu stačí
přetížíme-li pro třídu Retezec operátor +. Přetěžování operátorů znamená, že definujete vlastní funkci, která bude volána při použití daného operátoru a provede pak potřebné operace. Jak je možné, že překladač ví, kterou funkci má zavolat? K tomu slouží klíčové slovo operator před deklarací funkce; dalším vodítkem je typ proměnných použitých s operátorem ve výrazu.
V zásadě můžete funkce pro přetížení operátorů definovat dvěma způsoby:
1.) jako členskou funkci dané třídy
2.) jako friend funkci.
Poznámka:
friend neboli přátelská funkce je další vymožeností jazyka C++. Umožňuje deklarovat ve třídě nečlenskou funkci s klíčovým slovem friend. A tato funkce má pak přístup k datům třídy jako by byla členskou funkcí.

Pro třídu Retezec použijeme oba typy funkcí -jednu členskou pro přetížení operátoru += a druhou friend pro operátor +.

Otevřete soubor TESTIK.H a vložte do public pod řádek
void SetAt(int pos,char zn) { assert(pos < m_delka); m_text[pos] = zn; };
deklaraci členské funkce pro operátor += a pod ni deklaraci friend funkce pro op
erátor + :

const Retezec& operator+=(const Retezec& ret);
friend Retezec operator+(const Retezec& A, const Retezec& B);

Členská funkce pro operator += přičte předaný řetězec ret ke svému řetězci uloženému v členské proměnné m_text a vratí referenci na výsledný řetězec, tj. vlastně sama na sebe.
Friend funkce sečte řetězce A a B a vrátí přímo výsledný objekt třídy Retezec. Tato funkce vytváří lokální objekt třídy Retezec pro součet a nemůže vrácet pouze referenci na něj, protože tento objekt zanikne po sko
nčení funkce a reference by tedy odkazovala kdoví kam.

Při pohledu na deklarace obou funkcí operátoru si snadno představíte, jak překladač interpretuje řádek vašeho zdrojového kódu s danými operátory:
Např. ret1 += ret2; se přeloží jako ret1.operator+=(ret2
); a ret1 + ret2 jako operator+(ret1,ret2);

Zbývá definovat funkce. Otevřete proto soubor RETEZ.CPP a přidejte na konec následující řádky:

//členská funkce pro přetížení operátoru +=
const Retezec& Retezec::operator+=(const Retezec& ret)
{
strcat(m_text, r
et.m_text);
m_delka = strlen(m_text);
return (*this);
}

//definice přátelské funkce pro operátor +
Retezec operator+(const Retezec& A, const Retezec& B)
{
Retezec pom(A);
pom += B;
return pom;
}

U členské funkce operator+= jsme narazili na další nový pojem -ukazatel this. Bez zbytečných keců this je ukazatel na vlastní objekt - ukazatel sama na sebe. Funkce má vracet referenci sama na sebe, což je realizováno příkazem
return (*this);
Druhá - friend - funkce využívá nejprve třetího konstruktoru, který jsme právě vytvořili, ke konstrukci pomocného objektu třídy Retezec jménem pom inicializovaného přímo řetězcem A. Pak použije čerstvě napsanou funkci operator+= k přičtení řetězce B.

S dosud vytvořenými funkcemi můžeme psát pouze výrazi, kde jsou na obou stranách objekty třídy Retezec. Abychom mohli k objektu Retezec přičítat také textové konstanty typu "ahoj", musíme definovat další verze funkcí pro operátory += a +, které budou jako parametr brát ukazatel na char.

 

V kroku 6 definujeme další funkce pro operátory a vyzkoušíme třídu Retezec.