Na kurzech se velmi Φasto setkßvßm s dotazem,
jak² je rozdφl mezi Üablonovou verzφ seznamu (CList) a t°φdnφ verzφ (CObList).
Vzhledem k tomu, ₧e neexistuje jednoznaΦnß odpov∞∩ typu: zßsadn∞ pou₧φvejte CList
nechßme prob∞hnout boj mezi ob∞ma t°φdami a to v n∞kolika kolech.
Abychom mohli oba p°φstupy srovnßvat, vytvo°φme si nßsledujφcφ
t°φdu (pro jednoduchost uvßdφm pouze deklarace):
class PRO_Ancest : public CObject
{
// Data
// -----------------------------------------------
public:
int m_nData;
// Konstrukce
// -----------------------------------------------
PRO_Ancest();
// Virtußlnφ operace
// -----------------------------------------------
virtual void Print();
virtual void Serialize(CArchive &ar);
} |
Soupe°e mßme, mßme i s Φφm bojovat (₧e by C++?), tedy vzh∙ru do
bitvy.
Kolo prvnφ - univerzßlnost
èablona CList nßm umo₧≥uje vytvß°et obousm∞rn∞
vßzanΘ seznamy libovolnΘho typu, p°iΦem₧ tento typ je urΦen a₧ v definici
prom∞nnΘ (v∞tÜinou ΦlenskΘ prom∞nnΘ). Naopak t°φda CObList umo₧≥uje
vytvß°et pouze seznamy ukazatel∙ na objekty typu CObject. Vezmeme-li
tedy hledisko univerzßlnosti, vφt∞zem je Üablonovß verze seznamu a dostßvßme se na
sk≤re 1:0 pro Üablony..
// Definice seznamu ukazatel∙ na CObject a potomky
CObList oListCla;
// Definice seznamu ukazatel∙ na PRO_Ancest a potomky
CList<PRO_Ancest*, PRO_Ancest*> oListTem;
// Vytvo°enφ n∞jak²ch instancφ
PRO_Ancest *poAnc = new PRO_Ancest();
// Vlo₧enφ do prvnφho seznamu
oListCla.AddTail(poAnc);
// Vlo₧enφ do druhΘho seznamu
oListTem.AddTail(poAnc); |
Jak je vid∞t, tak mezi Üablonovou a t°φdnφ verzφ nenφ patrn²
₧ßdn² rozdφl a sk≤re tedy z∙stßvß stßle na 1:0.. Ale to je jen zdßnφ, kterΘ
hned vyvrßtφme v nßsledujφcφm fragmentu k≤du:
Kolo druhΘ - bezpeΦnost
// Vytvo°φme instanci t°φdy, kterß d∞dφ z CObject
CWnd *poWnd = new CWnd();
oListCla.AddTail(poWnd); // OK
oListTem.AddTail(poWnd); // Synt. chyba |
A je to tady - vlo₧enφ ukazatele na instanci t°φdy CWnd do
seznamu je asi chyba, to je z°ejmΘ, ale t°φdnφ verze to za chybu nepova₧uje, kde₧to
pro Üablonovou verzi to chyba je, a to dokonce syntaktickß. Dφky tomu, ₧e Üablonovß
verze je konkrΘtn∞jÜφ, podlΘhß k≤d lepÜφ syntaktickΘ kontrole. Z toho plyne, ₧e
Üablony zφskßvajφ bod a sk≤re je 2:0.
Podφvejme se na p°φstup k prvk∙m v seznamu (nap°φklad k tomu poslednφmu):
PRO_Ancest *poAncest;
poAncest = (PRO_Ancest*) oListCla.GetTail(); // p°etyp. je nutnΘ
poAncest = oListTem.GetTail(); |
A vzhledem k tomu, ₧e p°etypovßnφ nenφ v∙bec bezpeΦnß technika
(lze p°etypovat cokoli na cokoliv), zφskßvß Üablona dalÜφ bod a posouvß sk≤re na 3:0
ve sv∙j prosp∞ch.
Kolo t°etφ - perzistence
Poslednφ disciplφnou, ve kterΘ nechßme seznamy sout∞₧it, je
perzistentnost (uklßdßnφ na disk) - mechanismus serializace. Jak Üablona CList,
tak i t°φda CObList majφ virtußlnφ metody Serialize pracujφcφ s archivem.
Uklßdßnφ by tedy vypadalo takto:
// instance ar je typu CArchive& a zφskali jsme ji nap°φklad
// v metod∞ Serialize dokumentu
oListCla.Serialize(ar);
oListTem.Serialize(ar); |
Zdß se, ₧e sk≤re z∙stane stejnΘ, ale nenφ tomu tak, proto₧e bod
p°ekvapiv∞ zφskßvß t°φdnφ verze seznamu - stav tedy je 3:1. Äe
by nespravedliv² rozhodΦφ? V∙bec ne! Je to za to, ₧e Üablonovß verze ulo₧φ
naprostΘ nesmysly. Musφme si vysv∞tlit jak fungujφ metody Serialize v
jednotliv²ch p°φpadech. T°φdnφ verze Serialize d∞lß to, ₧e krom∞
internφch dat zavolß pro vÜechny vlo₧enΘ instance jejich metody Serialize, Φφm₧
jφm dß mo₧nost ulo₧it se. èablonovß verze krom∞ ulo₧enφ internφch dat ud∞lß
to, ₧e na disk ulo₧φ ukazatele, kterΘ po vypnutφ a zapnutφ samoz°ejm∞ ztrßcejφ
v²znam a pokud k nim p°istoupφme, dojde pravd∞podobn∞ k pßdu aplikace.
Zßv∞r
V²sledek 3:1 asi mluvφ za vÜe. VÜude kde to jen
lze, pou₧φvejme ÜablonovΘ verze (platφ i pro CArray a CMap), kterΘ
jsou bezpeΦn∞jÜφ a univerzßln∞jÜφ. JedinΘ na co musφme dßvat pozor, je
pou₧itφ mechanismu Serialize, kter² u Üablonov²ch verzφ musφme
implementovat vlastnφmi silami, co₧ ale nenφ nic slo₧itΘho (t°i °ßdky k≤du). |