-
Nßsledujφcφ funkce provßdφ °azenφ n prvk∙ pole typu int podle
velikosti.
void Razeni(int *a,
int n){
for (int w
= 0; w < n; ++w){
int k = w;
for (int l = w+1; l < n; l++) if (a[l] < a[k]) k = l;
if (k != w) {
int s = a[w];
a[w] = a[k];
a[k] = s;
}
}
}
╪azenφ prvk∙ pole se vyskytuje Φasto a bylo by tedy vhodnΘ tuto funkci
vlo╛it do knihovny. ProblΘm je, ╛e ne v╛dy pot°ebujeme se°adit prvky typu
int.
M∙╛eme vyjφt z uvedenΘho °e╣enφ a kdy╛ budeme pot°ebovat °adit pole s prvky
jinΘho typu, staΦφ nahradit v╣echna klφΦovß slova int oznaΦenφm
novΘho typu. To ale nenφ nejlep╣φ nßpad; co kdy╛ n∞kterΘ int zapomeneme
zm∞nit nebo zm∞nφme i int, kterΘ se typu prvk∙ °azenΘho pole net²kß.
Nabφzejφ se nßm ale dv∞ rozumn∞j╣φ °e╣enφ.
V╣echny v²skyty klφΦovΘho slova int, kterΘ oznaΦujφ typ °azenΘho
pole, nahradφme n∞jak²m obecn²m identifikßtorem, nap°. TYP a tomuto
identifikßtoru dßme v²znam pomocφ typedef. Nap°.
typedef int TYP;
Vyzkou╣ejte zm∞nit na╣i funkci v tomto smyslu.
-
DruhΘ °e╣enφ je deklarovat celou funkci jako makro, jeho╛ parametrem bude
typ °azenΘho pole:
#define RAZENI(TYP)
void Razeni(TYP *a, int n){
\
for (int w
= 0; w < n; ++w){
\
int k = w;
\
for (int l = w+1; l < n; l++) if (a[l] < a[k]) k = l;
\
if (k != w) {
\
TYP s = a[w];
\
a[w] = a[k];
\
a[k] = s;
\
}
\
}
\
}
Vyzkou╣ejte v n∞jakΘm programu.
-
Jazyk C++ nabφzφ lep╣φ °e╣enφ p°edchozφho problΘmu a to pou╛itφ ╣ablony.
Naprogramujeme funkci Razeni jen jednou a to jako ╣ablonu. Typ prvk∙
pole bude parametrem tΘto ╣ablony. P°ekladaΦ pak v p°φpad∞ pot°eby vytvo°φ
podle tΘto ╣ablony funkci s po╛adovan²mi vlastnostmi (podle typu urΦenΘho
parametrem ╣ablony). ⌐ablony se v mnohΘm podobajφ makr∙m, zpracovßvß je
ale p°ekladaΦ a ne preprocesor. Deklarace ╣ablony v programu p°edstavuje
abstraktnφ vzor, podle kterΘho je p°ekladaΦ schopen definovat celΘ skupiny
funkcφ. Funkce vytvo°enΘ podle ╣ablony naz²vßme instance ╣ablony. V C++
m∙╛eme deklarovat ╣ablony normßlnφch funkcφ, ╣ablony t°φd a jejich metod.
Deklaraci ╣ablony m∙╛eme v programu C++ zapsat pouze na ·rovni souboru
a mß tento obecn² tvar:
template<seznam_par>deklarace_╣ablony
Za klφΦov²m slovem template nßsleduje v lomen²ch zßvorkßch seznam
formßlnφch parametr∙ ╣ablony. Jsou to formßlnφ parametry odd∞lenΘ Φßrkami.
⌐ablony mohou mφt typovΘ a hodnotovΘ parametry. HodnotovΘ parametry jsou
parametry, s jak²mi se setkßvßme u obyΦejn²ch funkcφ. Mohou b²t skalßrnφch
typ∙. Nelze pou╛φt objektovΘ typy nebo pole. Nelze zde takΘ pou╛φt v²pustku.
U hodnotov²ch parametr∙ m∙╛eme p°edepsat implicitnφ hodnoty. TypovΘ parametry
jsou uvedeny klφΦov²m slovem class (u nov∞j╣φch p°ekladaΦ∙ je zde
klφΦovΘ slovo typename) a specifikujφ datovΘ typy. SkuteΦn²m parametrem
╣ablony, kter² odpovφdß formßlnφmu parametru, m∙╛e b²t oznaΦenφ libovolnΘho
datovΘho typu. Deklarace_╣ablony znamenß deklaraci normßlnφ funkce,
objektovΘho typu nebo metody podle obvykl²ch pravidel. V tΘto deklaraci
mohou b²t n∞kterΘ konstanty nahrazeny hodnotov²mi parametry a n∞kterß oznaΦenφ
typ∙ typov²mi parametry.
Nejd°φve se budeme zab²vat ╣ablonami °adov²ch funkcφ. ⌐ablona °adovΘ
funkce musφ mφt pouze typovΘ parametry. Jako p°φklad si uvedeme deklaraci
╣ablony funkce Razeni:
template<class
TYP> void Razeni(TYP *a, int n){
for (int w
= 0; w < n; ++w){
int k = w;
for (int l = w+1; l < n; l++) if (a[l] < a[k]) k = l;
if (k != w) {
TYP s = a[w];
a[w] = a[k];
a[k] = s;
}
}
}
⌐ablona Razeni mß jeden formßlnφ parametr TYP, kter²
p°edstavuje datov² typ. SkuteΦn²m parametrem tΘto ╣ablony m∙╛e b²t libovoln²
datov² typ, pro kter² jsou definovßny v╣echny operßtory pou╛itΘ pro tento
typ v ╣ablon∞. Instance ╣ablony normßlnφ funkce budou funkce se stejn²m
identifikßtorem, kterΘ se budou li╣it typem parametr∙. M∙╛eme je generovat
bu∩ explicitn∞ nebo implicitn∞. ZaΦneme u implicitnφho generovßnφ instancφ.
P°edpoklßdejme, ╛e jsme v programu deklarovali v²╣e uvedenou ╣ablonu Razeni.
Je-li a pole typu int, pak p°φkaz
Razeni(a, 10);
zp∙sobφ, ╛e p°ekladaΦ automaticky vytvo°φ instanci void Razeni(int
*, int). Podobn∞ deklarujeme-li v programu ╣ablonu
template<class
T> T max(T a, T b){
return a <
b ? b : a;
}
p°φpadn∞ pro nov∞j╣φ p°ekladaΦe
template<typename
T> T max(T a, T b){
return a <
b ? b : a;
}
a prom∞nnΘ x a y typu int, zp∙sobφ zßpis
int k = max(x, y);
╛e se prom∞nnΘ k p°i°adφ hodnota v∞t╣φho z Φφsel ulo╛en²ch v
x
a y. Bude-li ale z typu char, pak zßpis
z = max(x, z);
je chybn², nebo╗ takovou funkci podle na╣φ ╣ablony vytvo°it nelze.
⌐ablona max toti╛ p°edpoklßdß, ╛e typy obou parametr∙ jsou shodnΘ.
⌐ablona nenahrazuje prototyp funkce, tak╛e nelze spolΘhat na konverzi parametr∙.
To znamenß, ╛e pokud bychom deklarovali v programu konstantu
const int N = 1000;
a pokusili se vytvo°it instanci ╣ablony Razeni zßpisem
Razeni(a, N);
protestoval by p°ekladaΦ, ╛e neumφ najφt funkci Razeni(int *, const
int) a my bychom museli pou╛φt p°etypovßnφ
Razeni(a, (int)N);
nebo explicitnφ vytvo°enφ instance jak je uvedeno dßle. Pokuste se
vyzkou╣et ╣ablonu funkce Razeni v n∞jakΘm programu.
-
Explicitnφ generovßnφ funkcφ se pon∞kud li╣φ ve star╣φch a nov∞j╣φch p°ekladaΦφch
C++. V nov²ch p°ekladaΦφch (odpovφdajφcφch ANSI C++ - nap°. Borland C++
5.0) se pro explicitnφ generovßnφ instancφ pou╛φvß syntaxe
template prototyp;
To znamenß, ╛e instanci ╣ablony Razeni vytvo°φme zßpisem
template void Razeni(int
*, int);
a instanci ╣ablony max zßpisem
template double max(double,
double);
Tyto deklarace nahrazujφ prototyp, tak╛e p°ekladaΦ m∙╛e provßd∞t konverze
parametr∙.
N∞kdy se dostaneme do situace, kdy pro urΦit² typ parametr∙ nßm instance
vytvo°enß podle ╣ablony nevyhovuje. Nic nßm nap°. nebrßnφ generovat instanci
char
* max(char *, char *), kterß bude porovnßvat dva znakovΘ °et∞zce podle
adresy. Pro nßs mß ale podstatn∞ v∞t╣φ v²znam porovnßvßnφ znakov²ch °et∞zc∙
podle abecedy. V C++ nßm na╣t∞stφ deklarace ╣ablony nebrßnφ, abychom definovali
funkci se stejn²m jmΘnem a s pot°ebn²m typem parametr∙:
char * max(char *a,
char *b){
...// porovnßnφ
°et∞zc∙
}
Tato deklarace zastφnφ ╣ablonu (p°esn∞ji °eΦeno poklßdß ji za instanci
╣ablony) a nemusφme se obßvat, ╛e by p°ekladaΦ podle ╣ablony vytvo°il nesmyslnou
funkci.
-
Deklarace ╣ablony t°φdy nebo metody mß op∞t tvar
template<sez_par>deklarace;
St°ednφk na konci je podle normy nezbytn². ⌐ablony t°φd a jejich metod
mohou mφt (na rozdφl od ╣ablon normßlnφch funkcφ) nejen typovΘ, ale i hodnotovΘ
parametry. SkuteΦnΘ hodnotovΘ parametry p°i pou╛itφ ╣ablony musφ b²t konstantnφ
v²razy, tj. musφ je um∞t vyhodnotit ji╛ p°ekladaΦ. V tΘto deklaraci m∙╛eme
k oznaΦenφ typu pou╛φt typovΘ formßlnφ parametry a jako konstanty pou╛φt
hodnotovΘ formßlnφ parametry. V deklaraci ╣ablony t°φdy m∙╛eme zapsat i
vlo╛enΘ metody a vlo╛enΘ sp°ßtelenΘ funkce. Ostatnφ metody musφ mφt svΘ
vlastnφ ╣ablony. V nßsledujφcφm p°φkladu deklarujeme ╣ablonu t°φdy pro
prßci s dynamicky alokovan²m jednorozm∞rn²m polem prom∞nnΘ dΘlky. Jako
parametr ╣ablony zadßme poΦet prvk∙ pole a jejich typ.
template<class
T, int N =2> class Pole {
int delka;
T* p;
public:
Pole(T r=0);
Pole(Pole&);
~Pole() {delete
p;};
Pole&
operator= (Pole&);
T& operator[]
(int i) {return p[i];}
Pole operator*(double);
friend Pole<T,N>
operator* (double d, Pole<T,N>& Q) {return Q*d;}
};
Tato ╣ablona mß typov² parametr T a hodnotov² parametr N
(mß implicitnφ hodnotu). Identifikßtor Pole je jmΘno ╣ablony. V
deklaraci ╣ablony t°φdy je lze pou╛φvat bez parametr∙, p°i ostatnφch pou╛itφch
v╣ak musφ b²t spojeno se skuteΦn²mi parametry. Pro ╣ablonu t°φdy, kterß
obsahuje ukazatel na dynamicky alokovanΘ pole, jsme museli deklarovat kopφrovacφ
konstruktor, destruktor a p°i°azovacφ operßtor. Snadn² p°φstup ke slo╛kßm
tohoto pole nßm umo╛nφ operßtor indexovßnφ. Dßle jsme zde deklarovali operßtor
*, kter² vynßsobφ v╣echny prvky pole dan²m Φφslem. Operßtor nßsobenφ Φφslem
zprava deklarujeme jako metodu (prvnφ operand je Pole), operßtor
nßsobenφ Φφslem zleva (v po°adφ Φφslo*Pole) deklarujeme jako sp°ßtelenou
funkci. Operßtor indexovßnφ a destruktor jsme zde deklarovali jako vlo╛enΘ
metody, nebo╗ jsme zapsali jejich definiΦnφ deklarace v t∞le ╣ablony t°φdy.
Pro ostatnφ metody musφme deklarovat zvlß╣tnφ ╣ablony. Podφvejme se na
╣ablonu implicitnφho a kopφrovacφho konstruktoru a operßtoru nßsobenφ Φφslem
zprava:
template<class
T, int N> Pole<T,N>::Pole(T r) : delka(N) {
p = new T[delka];
if (!p) Chyba();
for (int i
= 0; i < N; i++) p[i] = r;
}
template<class
T, int N> Pole<T,N>::Pole(Pole<T,N>& P): delka(P.delka) {
p = new T[delka];
if (!p) Chyba();
for (int i
= 0; i < N; i++) p[i] = P.p[i];
}
template<class
T, int N> Pole<T,N> Pole<T,N>::operator*(double d) {
Pole<T,N>
Q = *this;
for (int i
= 0; i < N; i++) Q.p[i] = Q.p[i]*d;
return Q;
}
Mimo deklaraci ╣ablony t°φdy musφme spolu se jmΘnem ╣ablony uvßd∞t
v╛dy parametry. Jedinou v²jimkou je ╣ablona konstruktoru, kde se parametry
uvßd∞jφ pouze jednou, ve jmΘnu typu vlevo od dvou dvojteΦek. Je asi jasnΘ,
╛e ╣ablony metod, kterΘ jsou deklarovßny samostatn∞, nejsou souΦßstφ deklarace
╣ablony t°φdy. MΘn∞ z°ejmΘ ale m∙╛e b²t, ╛e souΦßstφ deklarace ╣ablony
t°φdy nenφ ani deklarace vlo╛enΘ sp°ßtelenΘ funkce. Proto jsme v deklaraci
druhΘho operßtoru * pou╛ili zßpis Pole<T,N>.
Vytvo°φme-li instanci ╣ablony t°φdy, vznikne objektov² typ. Pod tφm
se skr²vß nejen jmΘno a struktura t°φdy, ale takΘ k≤dy metod a p°φpadnΘ
instance statick²ch atribut∙. Nejjednodu╣╣φ zp∙sob jak vytvo°it instanci
t°φdy je p°φmΘ pou╛itφ v deklaraci. Nap°. zßpis
Pole<int, 15>
Ppp(99);
zp∙sobφ vytvo°enφ typu jmΘna Pole<int, 15>. SouΦasn∞ vznikne
instance Ppp nov∞ vytvo°enΘho typu. Obvykle je ale v²hodn∞j╣φ vytvo°it
nejprve nov² typ, tedy instanci ╣ablony, pomocφ deklarace typedef:
typedef Pole<int,
15> intpole15;
P°φkazem
typedef Pole<long>
lpole;
vytvo°φme typ Pole<long, 2>, nebo╗ p°ekladaΦ pou╛ije implicitnφ
hodnotu parametru N. Norma ANSI C++ umo╛≥uje p°edepsat explicitnφ
generovßnφ t°φdy zßpisem
template class Pole<int,
2>;
KlφΦovΘ slovo class p°ed identifikßtorem je nezbytnΘ. Vyzkou╣ejte
pou╛φt ╣ablonu Pole v n∞jakΘm programu.
-
V ╣ablon∞ t°φdy m∙╛eme samoz°ejm∞ specifikovat takΘ statickΘ slo╛ky. Ka╛dß
instance takovΘto ╣ablony, kterou podle tΘto ╣ablony vytvo°φme, bude obsahovat
svΘ vlastnφ instance statick²ch slo╛ek. V takovΘm p°φpad∞ ov╣em pot°ebujeme
pro ka╛dou instanci ╣ablony takΘ definiΦnφ deklaraci t∞chto statick²ch
atribut∙; ta m∙╛e obsahovat i inicializaci. I zde si ov╣em m∙╛eme vypomoci
╣ablonou, tentokrßt ╣ablonou statickΘ slo╛ky. Nap°.
template<class
T> class vektor {
static T pocet;
T p[10];
public:
vektor() {for
(int i=0; i < 10; i++) p[i] = 0; pocet++;}
...
};
template<class
R> R vektor<R>::pocet = 0;
// generujeme instance
vektor<int> t;
vektor<double>
r;
Instance vektor<int> bude mφt statick² atribut int vektor<int>::pocet;
instance vektor<double> bude mφt statick² atribut double vektor<double>::pocet.
Oba budou inicializovßny hodnotou 0. Instance statick²ch atribut∙ se zde
vytvo°φ automaticky p°i vytvß°enφ instancφ ╣ablony vektor. ⌐ablonu
statickΘ slo╛ky m∙╛eme pochopiteln∞ nahradit obyΦejnou definiΦnφ deklaracφ.
To znamenß, ╛e p°edchozφ p°φklad m∙╛eme zapsat takΘ takto:
template<class
T> class vektor {
static T pocet;
...
};
vektor<int> t;
int vektor<int>::pocet
= 0;
vektor<double>
r;
double vektor
Pokud nßm pro urΦitΘ hodnoty parametr∙ nevyhovuje instance vytvo°enß
podle ╣ablony, m∙╛eme ji deklarovat podle sv²ch p°edstav. Mß-li p°ekladaΦ
chßpat nov∞ deklarovan² typ jako instanci existujφcφ ╣ablony, musφ se jmΘno
typu shodovat se jmΘnem ╣ablony a musφ obsahovat skuteΦnΘ parametry. Nap°.
class Pole<float,
100> {
int p[100];
public:
int& operator[]
(int i);
Pole<float,
100>::Pole(int m);
};
Pole<float, 100>::Pole(int
m = -1) {
for (int i
= 0; i < 100; i++) p[i] = m;
}
Pro parametry float a 100 pou╛ije p°ekladaΦ instanci,
kterou jsme zde p°edlo╛ili; pro ostatnφ hodnoty vytvo°φ instance podle
╣ablony.
⌐ablony p°edstavujφ mimo°ßdn∞ vhodn² nßstroj pro vytvß°enφ knihoven.
TakΘ skladovΘ t°φdy (t°φdy p°edstavujφcφ zßsobnφky, fronty, seznamy a jinΘ
struktury pro uklßdßnφ dat) se vyplatφ implementovat jako ╣ablony. ╪adu
p°φklad∙ ╣ablon najdeme v BorlandskΘ knihovn∞ skladov²ch t°φd.
-
Nynφ ji╛ jsme schopni programovat v jazyku C++. Kdy╛ ale
zaΦneme vytvß°et programy pro Windows, pak zjistφme, ╛e to nenφ jednoduchΘ.
API Windows (aplikaΦnφ programovΘ rozhranφ) je znaΦn∞ rozsßhlß kolekce
C funkcφ. Jejich pou╛itφ si ukß╛eme na p°φkladu. Nßsledujφcφ Φßst programu
zavede a zobrazφ bitovou mapu uprost°ed obrazovky:
HPALETTE
hPal;
BITMAPFILEHEADER
bfh;
BITMAPINFOHEADER
bih;
LPBITMAPINFO
lpbi = 0;
HFILE
hFile;
DWORD
nClrUsed, nSize;
HDC
hDC;
HBITMAP
hBitmap;
void
_huge *bits;
do
{
if ((hFile = _lopen(data.FileName, OF_READ)) == HFILE_ERROR) break;
if (_hread(hFile, &bfh, sizeof(bfh)) != sizeof(bfh)) break;
if (bfh.bfType != 'BM') break;
if (_hread(hFile, &bih, sizeof(bih)) != sizeof(bih)) break;
nClrUsed = (bih.biClrUsed) ? bih.biClrUsed : 1 << bih.biBitCount;
nSize = sizeof(BITMAPINFOHEADER) + nClrUsed * sizeof(RGBQUAD);
lpbi = (LPBITMAPINFO) GlobalAllocPtr(GHND, nSize);
if (!lpbi) break;
hmemcpy(lpbi, &bih, sizeof(bih));
nSize = nClrUsed * sizeof(RGBQUAD);
if (_hread(hFile, &lpbi->bmiColors, nSize) != nSize) break;
if (_llseek(hFile, bfh.bfOffBits, 0) == HFILE_ERROR) break;
nSize = bfh.bfSize-bfh.bfOffBits;
if ((bits = GlobalAlocPtr(GHND, nSize)) == NULL) break;
if (_hread(hFile, bits, nSize) != nSize) break;
hDC = GetDC(hWnd);
hBitmap = CreateDIBitmap(hDC, &(lpbi->bmiHeader), CBM_INIT,
bits, lpbi, DIB_RGB_COLORS);
if (hBitmap) {
LPLOGPALETTE lppal;
DWORD nsize = sizeof(LOGPALETTE) + (nClrUsed-1) * sizeof(PALETTEENTRY);
lppal = (LPLOGPALETTE) GlobalAllocPtr(GHND, nSize);
if (lppal) {
lppal->palVersion = 0x0300;
lppal->palNumEntries = (WORD) nClrUsed;
hmemcpy(lppal->palPalEntry, lpbi->bmiColors, nClrUsed * sizeof(PALETTEENTRY));
hPal = CreatePalette(lppal);
(void) GlobalFreePtr(lppal);
}
}
} while(FALSE);
if
(hFile != HFILE_ERROR) _lclose(hFile);
HPALETTE
oldPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
HDC
hMemDC = CreateCompatibleDC(hDC);
HBITMAP
oldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
BitBlt(hDC,
0, 0, (WORD)bih.biWidth, (WORD)bih.biHeight, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC,
oldBitmap);
DeleteDC(hMemDC);
SelectPalette(hDC,
oldPal, FALSE);
ReleaseDC(hWnd,
hDC);
if
(bits) (void)GlobalFreePtr(bits);
if
(lpbi) (void)GlobalFreePtr(lpbi);
Vidφme, ╛e takov² jednoduch² problΘm jako je zobrazenφ
bitovΘ mapy vy╛aduje znaΦn∞ slo╛it² k≤d. Usnadn∞nφ tΘto prßce spoΦφvß ve
vytvß°enφ t°φd, kterΘ obalujφ Φasto provßd∞nΘ programovΘ ·lohy Windows,
co╛ znaΦn∞ zv²╣φ produktivitu prßce programßtor∙. Po vytvo°enφ zaobalujφcφch
t°φd je m∙╛eme opakovan∞ pou╛φvat. Tφm vytvß°φme pracovnφ rßmce.
Pracovnφ rßmec je kolekce t°φd, kterΘ zjednodu╣╣ujφ
programovßnφ pro Windows zaobalenφm Φasto pou╛φvan²ch technik programovßnφ.
Pracovnφ rßmce naz²vßme knihovny t°φd.
Jednφm z pracovnφch rßmc∙ je Object Windows Library (OWL)
firmy Borland. S pomocφ tΘto knihovny m∙╛eme p°edchozφ Φßst programu zapsat
takto:
TDib
dib("Test.bmp");
TPalette
pal(dib);
TBitmap
bitmap(dib, &pal);
TClientDC
dc(*this);
dc.SelectObject(pal);
dc.RealizePalette();
TMemoryDC
memdc(dc);
memdc.SelectObject(bitmap);
dc.BitBlt(0,
0, bitmap.Width(), bitmap.Height(), memdc, 0, 0);
Vidφme, ╛e verze OWL je podstatn∞ krat╣φ a takΘ srozumiteln∞j╣φ.
Tyto p°φklady nßm ukßzaly, co je to pracovnφ rßmec. Pracovnφ rßmec p°ed
nßmi skr²vß detaily, kterΘ nemusφme znßt. Ve skuteΦnosti tato verze Φßsti
programu odpovφdß prvnφ verzi, pouze n∞kterΘ Φinnosti jsou ukryty v knihovn∞
t°φd. V╣e co pot°ebujeme v∞d∞t o objektech tvo°φcφch pracovnφ rßmec je
to, jak je pou╛φt v programu.
DobrΘ pracovnφ rßmce p°ebφrajφ pln∞ mo╛nosti OOP. OWL
a VCL (Visual Component Library) jsou vzorov²mi p°φklady objektov∞ orientovanΘho
programovßnφ. Pracovnφ rßmce usnad≥ujφ programovßnφ. Nev²hodou je to, ╛e
program zapsan² pomocφ pracovnφho rßmce je del╣φ a pomalej╣φ ne╛ stejn²
program zapsan² p°φmo v C. Zv²╣enφ produktivity programovßnφ tuto nev²hodu
ale p°evß╛φ.
Jednφm z prvnφch pracovnφch rßmc∙ je OWL firmy Borland.
Prvnφ verze OWL byl samostatn² produkt urΦen² pro prßci s p°ekladaΦem Borland
C++ verze 3. Postupn∞ vznikaly dal╣φ verze. Nap°. od verze OWL 2.5 byla
p°idßna podpora pro OLE v novΘ mno╛in∞ t°φd nazvan²ch OCF (Object Component
Framework). OCF nenφ technicky souΦßstφ OWL. Pracuje na stejnΘm principu
jako OWL, ale m∙╛e b²t pou╛ito nezßvisle na OWL. Poslednφ nejnov∞j╣φ verze
OWL je 5.
N∞kdy mezi OWL 1 a OWL 2 vzniklo MFC (Microsoft Foundation
Class Library). MFC je souΦßstφ p°ekladaΦe Microsoft Visual C++ a je dostupnß
i s p°ekladaΦi dal╣φch firem. MFC je knihovnou jinΘho typu ne╛ OWL. MFC
nespl≥uje zcela po╛adavky OOP.