Práce s MFC výjimkami (MFC a C++)

Dříve, když ještě neexistoval jazyk C++, se většina funkcí programovala tak, že při neúspěchu vracely nějakou chybovou hodnotu. Může se to zdát výhodné, ale pokud jste tvořili nějakou funkci, která mohla vracet jakoukoli hodnotu, tak na nějaké chybové stavy už prostě nezbylo místo. Nejen proto jazyk C++ zavedl výjimky. Když se nyní v programu něco nepovede, tak příslušná funkce vyvolá výjimku určitého typu a nadřazená funkce ji potom může zachytit a reagovat na ni například chybovým hlášením. V tomto článku chci však především popsat výjimky, které generují třídy MFC, a proto zde uvedu pouze malou ukázku použití standardních výjimek.

Jak zachytit a vyvolat výjimku

Výjimka se vyvolá pomocí klíčového slova throw , za nímž následuje proměnná, která určuje výjimku a je určitého datového typu. Pokud bychom tedy chtěli vyvolat výjimku typu int můžeme napsat:

... //Nějaká funkce
if(hodnota==spatnahodnota)
{
  throw 5;  //Výjimka typu int
}

K zachycení výjimky naopak slouží klíčová slova try a catch , za kterým v závorce následuje typ výjimky, kterou zachycuje. Blok s try určuje prostor, ve kterém výjimka může vzniknout a v bloku catch se potom jednotlivé výjimky ošetřují. Těchto bloků catch může být za sebou neomezeně mnoho a pokud chceme zachytit úplně všechny výjimky, zapíšeme místo typu výjimky tři tečky (...). Takto by se například zachytila naše výjimka typu int:

...
try
{
  Funkce(parametr);   //V této funkci může vzniknout výjimka typu int
}
catch(int i)        //Zachytit výjimku typu int
{
  MessageBox("Vznikla chyba!")
}
catch(...)      //Zachytit všechny další výjimky
{
  MessageBox("Neočekávaná chyba!")
}

MFC výjimky

V předchozím odstavci jste tedy viděli, jak se s výjimkami pracuje, a teď si povíme něco o MFC výjimkách.

Výjimky, které v třídách MFC vznikají, jsou všechny odvozeny z třídy CException , a pokud tedy chceme zachytit všechny výjimky, které mohou v MFC vzniknout, zapíšeme do bloku catch třídu CException. Z této třídy jsou potom odvozeny další výjimky, které blíže určují povahu chyby, která vznikla. Pozor ještě na to, že MFC výjimky se zachycují pomocí ukazatelů, protože jsou tvořeny na haldě a tudíž je nutno je po použití smazat.

Základní třída CException má celkem tři metody:

Delete - vymaže výjimku
GetErrorMessage - vrátí chybové hlášení do proměnné typu LPTSTR
Report error - zobrazí chybový messagebox s chybovým textem

Takto bychom tedy zachytili všechny MFC výjimky:

try
{
  ...  //Zde může vzniknout výjimka
}
catch(CException* e)
{
  e->ReportError(); //Oznámit chybu
  e->Delete();      //Vymazat výjimku
}

Z třídy CException potom dědí tyto třídy výjimek:

CFileException - vzniká při chybě, která nastane při práci se soubory (třída CFile)
CArchiveException - značí chybu při práci s archivem (třída CArchive)
CMemoryException - vzniká při nedostatku paměti (operátory new a delete)
CResourceException - vzniká při chybě s prostředky programu
CNotSupportedException - značí nepodporovanou akci

Myslím, že práce s těmito třídami je více než jednoduchá, ale pro jistotu tu uvedu ještě příklad na souborovou výjimku, která muže vzniknout například při pokusu vytvořit soubor na uzamčené disketě nebo při pokusu o otevření neexistujícího souboru.

try
{
  CFile file;
  file.Open("C:\\soubor.dat",CFile::modeRead);  //Zde může být výjimka
}
catch(CFileException* fe)
{
  fe->ReportError();
  fe->Delete();
}

Nakonec bych ještě dodal, že MFC výjimky má smysl zpracovávat pouze při práce s MFC třídami, takže pokud například otevíráte soubor pomocí funkce fopen , tak je jasné, že zde výjimka typu CFileException nemůže vzniknout.

UPOZORNĚNÍ: Jedná se o archiv článků z let 2003 - 2005, uvedené technologie či postupy již mohou být neaktuální.