# 3 Techniky

## 3.1 Techniky rozšiřování rámce

### 3.1.1 Rozšíření kódu

Problém registrace rozšíření volaného původním kódem: Jak se původní kód dozví o existenci rozšíření, které má volat?

Implementace rozšíření:

- Flexibilita v čase běhu (run time). Nové části programu mají formu dynamické knihovny (DLL, .so). Program se konfiguruje při nebo po spuštění. Protože rozšiřující části musí být někde vyjmenovány, je možno je postupně inicializovat, tj. spustit nějaý kód pro každý rozšiřující modul.Takový kód může modul zaregistrovat. Je platformově závislé, kdy se tak stane. Pro chování běhové podpory C++ programu platí standard, který nechává značnou volnost.
- Flexibilita v čase sestavení. Pevné i nové části programu mají formu vstupu pro linker (.o, .obj). Pro C++ existuje možnost spustit inicializační kód (a tudíž registraci) v každém přisestaveném modulu, ale standard nechává značnou volnost, kdy se tak stane
- Flexibilita při překladu. Pokud se nepoužjí speciální techniky (např. prohledávání adresářů a generování konfiguračních souborů z nalezených zdrojových souborů), registrace nováho modulu znamená zásah do původních zdrojových souborů.

#### 3.1.1.1 Běhová podpora C++ programů a inicializace modulu

- Statické proměnné jsou před spuštěním jakéhokoli kódu programu (v podstatě tedy v čase sestavení) inicializovány tak, že jejich paměťové místo obsahuje binární nuly.
- Pokud má proměnná inicializátor, nastavení se provede (přiřazením nebo spuštěním konstruktoru) v čase inicializace modulu.
- Standard vyžaduje, aby inicializace modulu byla provedena před voláním první funkce v modulu obsažené (motivací je zřejmě nevyžadovat potenciílně pracnou inicializaci modulů, které nebudou použity).
- Známé platformy inicializují moduly před spuštěním main().
- Pokud je volání každé funkce nějakého modulu závislé na registraci modulu a tudíž na provedení inicializace, podle normy nemusí být modul spuštěn vůbec.
- Na známých platformách tento přístup funguje bez problémů.
- Na platformě, která využívá možností C++ standardu, je možno dosáhnout korektní funkce voláním jedné funkce v každém modulu na začátku main().

#### 3.1.1.2 Problém inicializace registrační struktury

Registrace modulu v čase jeho inicializace vyžaduje spuštění metody v jiném modulu. Tato metoda pravděpodobně zapíše modul do datové struktury jako je vektor nebo seznam. Problém: tato datová struktura musí být provozuschopná a data v ní nesmí být přepsána.

Alespoň jedna část datové struktuty musí být inicializována dříve, než se prvý modul pokusí o registraci. Podle ní se dá poznat, že datová struktura ještě neexistuje nebo není inicializována.

Pořadí inicializace modulů není normou stanoveno.Podmínku včasné inicializace datové struktury lze splinit:

- tím, že datová struktura
  - nemé inicializátor
  - nemí konstruktor
  - je provozuschopná po statické inicializaci (nuly)
- nebo vynucením pořadí inicializace technikou, která se používá pro inicializaci cin a cout (viz C++ Annotated Reference Manual odst. 3.4), která ale vyžaduje poměrně speciální styl kódování.

### 3.1.2 Rozšiřování dat

#### 3.1.2.1 Dědičnost

Třídy, reprezentující hlavní datové struktury rámce jsou vybaveny metodami a datovými členy pro poskytování standardní funkčnosti rámce. Objektové programování nabízí možnost rozšířit tyto struktury užitím odvozených tříd na místě tříd původních. Tato celkem standardní technika vyžaduje:

- aby rámec pracoval s objekty, eventuálně dodanými zvnějšku, které by na požádání dodaly objekt (odvozený z) dané třídy - návrhový vzor Továrna; nebo
- aby nové objekty v rámci vznikaly jako klon objektů vzorových a eventuálně z vnějšku dodaných (objekty na to musí být náležitě vybaveny) - návrhový vzor Klonování.

Tento způsob rozšiřování je nepružný. Nechť tři různé uživatelské nástroje potřebují tři různá rozšíření A, B, C bázové třídy T. Aby tato rozšíření bylo možno použít, je nutno:

- Buď pracovat s uzávěrem rozšíření, tedy s třídou U, která dědí A, B a C. v tom případě moduly nejsou vzájemně nezávislé a nadto třída T musí být virtuálním předkem A, B a C, se všemi nepříjemnostmi, které z toho plynou.
- Nebo se musí mezi spuštěním nástrojů objekty překopírovat, což zabírá čas. Navíc, v datové struktuře provázané ukazateli není možno objekt jednoduše "vyměnit" za jiný. Obecně neznáme všechny objekty, které na daný objekt odkazují (i když datové struktury rámce jsou ve značné míře provázány obousměrně). Je tedy nutno tento problém řešit "idiomem piml" (pointer to implementation), tedy dvojdílnými objekty s pevnou "hlavičkou", na kterou se lze odkazovat, a s variabliní implementací, kterou lze vyměňovat. Cenou za takové řešení jsou dva objekty místo jednoho a dvě dereference namísto jedné prakticky ve všech případech.

Vzhledem k vlastnostem obou variant není přínos rozšiřování dědičností příliš velký.

#### 3.1.2.2 Asociace

Nechť uživatelský nástroj potřebuje rozšířit bázovou třídu T na odvozenou třídu A. Je také možné shrnout metody a datové členy, které má třída A proti třídě T navíc do třídy EA a zavést asociativní vztah mezi objekty tříd T a EA, mapř. objektem třídy `map` . Toto řešení má několik výhod:

- Asociace může být pro daný nástroj privátní a může jich existovat více současně.
- Je-li potřeba zapisovat pouze do rozšířených členů (členů třídy EA v našem případě), je možno ponechat přístup k členům T jen pro čtení, což je výhodou při paralelním přístupu k rámci.

Nevýhody:

- Čas traverzování takové asociace prakticky nemůže být lepší než logaritmický.
- Metody třídy A mají přístup k `protected` metodám a členúm třídy T, což přes asociaci nemůže platit.

#### 3.1.2.3 Atributy

Protože "přilepení" obecných členů k objektům se ukazuje jako obtížné, i omezená řešení mohou být užitečná. Mnoho případů, kdy je rozšíření potřeba, vyžaduje pouze binární atributy. K ošetření těchto případů stačí, aby

- takové atributy byly modelovány tříhodnotově (ano, ne, nenastaveno);
- příslušné objekty měly datový člen, který je vektorem takových položek nedefinovaného počtu složek;
- všechny složky tohoto vektoru měly počáteční hodnotu "nenastaveno";
- každý uživatelský modul mohl obdržet unikátní hodnotu (hodnoty) indexu v těchto vektorech.