Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Akce a Zpráva jako objekt v.2 - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Akce a Zpráva jako objekt v.2

V článku C++ - Akce a Zpráva jako objekt jsem představil dva objekty, jenž slouží k objektovému zabalení volání funkce nebo metody. V tomto článku si představíme vylepšenou druhou verzi.


actions2.zip Zdrojové soubory, obsahuje i tuples2

Nejdůležitější změny

Podpora tuplů až do 64 parametrů.
Nyní je možné vytvářet akce na funkce mající až 64 parametrů
Opravená chyba při použití "emptyTuple".
Předchozí verze bohužel trpěla chybou, kdy nešlo instanciovat akci nebo zprávu s nula parametry.
Rozdělení hlavičkových souborů
Knihovna má rozdělené hlavičkové soubory: actions.h a iactions.h. Definice tak rozdělily na část deklarující rozhraní a část, která rozhraní implementuje. Deklaraci rozhraní (iactions.h) můžeme použít všude tam, kde nám postačí pouze znát toto rozhraní, ale nepotřebujeme instanciovat akce (například u příjemce). Naopak, pokud potřebujeme instanciovat akce, musíme zahrnout i implementaci (actions.h). Zde je také výhodné vkládat actions.h pouze do souborů s příponou *.cpp, aby se tak předešlo zdlouhavému překládání souborů, které explicitně nepotřebují akce instanciovat.

K čemu akce a zprávy

V článku C++ - Akce a Zpráva jako objekt podrobně popisuji, jaké výhody můžeme získat tím, že pouhé volání funkce nebo metody zabalíme do objektu. Stručně si to shrňme.

Hlavní výhodou je bezespory fakt, že bez ohledu na to, co voláme a kolik to má parametrů, je samotné zavolání funke omezeno jen na vyvolání jedné metody objektu. To umožňuje volání funkce nebo metody delegovat. Volání připravíme, a pak jej delegujeme. Delegované volání může proběhnout jindy, než zrovna potřebujeme, může být naplánováno, může být rozesíláno. Může být připojeno k ovládacímu prvku v grafickém UI (např. tlačítko).

Zatím rozlišujeme dva druhy volání: Zprávu (Message) a Akci (Action).

Zpráva (Message)
Je jakousi skutečnou implementací představou zprávy zaslané objektu podle OOP. Jedná se o objekt, který obsahuje jméno metody a parametry, které se mají zavolat nad nějakým objektem. V UML si můžeme zprávu představit jako obdélníček doprovázející šipku představující zaslání zprávy.
Samotný obdélníček lze připojit k libovolné šipce, a stejně tak objekt Message neobsahuje cíl, neboli konkrétní specifikaci objektu, který bude zavolán. Tuto informaci musíme dodat až v okamžiku, kdy zprávu posíláme.
Použití objektu Message je vhodné zejména u distribučních delegátů, nebo delegátů, kteří mají informovat objekt, které v době vzniku zprávy ještě neexistuje, nebo který dodá sám delegát z jiného zdroje.
Akce (Action)
Objekt akce je jednoduší, protože ke svému provedení již nepotřebuje žádné další informace. Akci spustí delegát prostým zavoláním metody Run(). Akce může být vykonána zavoláním standardní (globální) funkce, nebo funkce patřící do některého prostoru jmeno (namespace). Akce může být také vykonána zavoláním metody na objektu, který je však již předem znám - a musí být samozřejmě znám i v době zavolání.
Použití objektu Action je vhodné zejména o delegátů sledující různé události. Může se jednat o plánovače - spuštění v zadaný čas, dále pak reakce například na činnost uživatele. V neposlední řadě jsou to akce přenesené do jiného vlákna a tam spuštěné.

Vytvoření zprávy nebo akce

Zpráva není nic jiného než instance potomka rozhraní Message. Akce zase není nic jiného než instance potomka Action. V obou případech jsou to šablony, u kterých musíme specifikovat typ návratové hodnoty. Naštěstí to není povinné a pokud typ neuvedeme, předpokládá se void. U zprávy musíme navíc specifikovat třídu nebo rozhraní cílového objektu

 Action<bool> *msg1; //ukazatel na zprávu, která vrací bool
Action<> *msg2; //ukazatel na zprávu, která vrací void
Message<MyIfc, bool> *act1; //ukazatel na zprávu, která očekává třídu nebo rozhraní MyIfc a která vrací bool
Message<MyIfc> *act2; //ukazatel na zprávu, která očekává třídu nebo rozhraní MyIfc a která vrací void

Potomky obou rozhraní můžeme samozřejmě vytvořit ručně, takže implementujeme příslušnou metodu Run. Ale to je naštěstí zbytečné, protože obě třídy už mají připravené potomky v podobě šablon, které vytvoření příslušného potomka usnadní.

Vytvoření zprávy

K vytvoření zprávy použijeme statickou metodu Make(...). Můžeme ji použít přímo tam, kde se očekává parametr typu Message, nebo ji můžeme spojit s metodou Clone() a získat tak ukazatel. Přímo deklarovat zprávu není moc výhodné, protože zápis instance šablony díky použití tuple je většinou velice dlouhé a nepřehledné.

Volání funkce

void foo(const Message<MyIfc> &msg) {...}; //nějaká funkce

foo(Message<MyIfc>::Make(&MyIfc::bar, (tuple|param1,param2,param3) );

Získání ukazatele

Message<MyIfc> *msgptr = Message<MyIfc>::Make(&MyIfc::bar, (tuple|param1,param2,param3) ).Clone();

V obou případech vytváříme zprávu pro objektu implementující rozhraní MyIfc, která bude volat funkci bar a předá jí tři parametry, V prvním případě je zpráva předána jako reference. V druhém případě je zpráva alokována dynamicky, takže ji nesmíme zapomenou zničit příkazem delete

Jak už bylo řečeno, vytvořením zprávy nedojde k zavolání specifikované metody. Vlastně to ani není možné, protože neznáme cíl zprávy. K zavolání dojde až když někdo zavolá metodu Run(...)

MyIfc *ifc = ...; //pointer na nějaký objekt
msgptr->Run(ifc); //zavolej připravenou zprávu.

Delegát má tedy velice jednoduchou práci. Stačí, když někde obstará objekt, a pak na ten objekt pošle zprávu. Delegát sám osobě vůbec nemusí obsah zprávy znát, nemusí znát ani parametry. Dokonce ani nemusí znát vlastní rozhraní, postačí, když bude vědět, že existuje.

Vytvoření akce

Vytvoření akce je podobné, stejně jako při vytvoření zprávy, buď akci vytváříme jako parametr funkce, nebo ji alokujeme dynamicky. Přímá deklarace by opět byla velmi komplikovaná.

Volání funkce

void foo(const Action<> &act) {...}; //nějaká funkce

foo(Action<>::Make(&bar, (tuple|param1,param2) );

Získání ukazatele

Action<> *actptr = Action<>::Make(&bar, (tuple|param1,param2) ).Clone();

Tímto způsobem vytváříme akci, která volá globální funkci bar a předá jí dva parametry. U akcí však existuje ještě jedna varianta příkazu Make. Tato varianta má tři parametry, kde prvním parametrem je objekt, který voláme a druhým parametrem je v tomto případě metoda, kterou voláme

foo(Action<>::Make(&myobject, &MyObj::bar, (tuple|param1,param2) );

Pokud předpokládáme, že myobject je typu MyObj, pak výsledkem je akce, která volá na objektu myobject metodu bar a předá jí dva parametry.

Všimněte si, že výsledkem v obou případech je objekt implementující rozhraní Action. Delegát, který posléze bude na akci volat Run už nemusí nic vědět o tom, že objekt je volání globální funkce, nebo metody objektu. Vůbec nemusí objekt ani funkci uložené akci znát, ani nemusí nic vědět o parametrech.

Vyvolání akce, jak už bylo řečeno, je jednoduché

actptr->Run(); //zavolej připravenou akci.

Volání jako objekt

V knihovně actions.h najdeme také samotné volání jako objekt. Volání v C++ je implementování pomocí ukazatele na funkci. Bohužel pokud voláme metodu objektu, je zápis jiný, než pokud voláme globální funkci
Volání funkce

void (*fn)(int a, int b) = &bar;
fn(10,20);

Volání metody

void (MyObj::*fn)(int a, int b) = &MyObj::foo;
(myobj->*fn)(10,20);

V rámci knihovny v prostoru jmenu (namespace) "Tuples" můžeme vytvářet objekty představující volání nějaké funkce nebo metody.

  • Tuples::FunctionPointer
  • Tuples::MethodPointer
Tuples::FunctionPointer<int (*)(int a, int b), int> fncall(&bar);
bar( (tuple|10,20) );
//----------------
Tuples::MethodPointer<MyObj *,int (MyObj::*)(int a, int b), int> mtdcall(&myobj,&MyObj::foo);
mtdcall( (tuple|10,20) );

Všimněte si, že volání funkce nebo metody má stejný zápis (pomocí operátoru ()). Toho můžeme využít v případě, že například píšeme šablonu, ve které chceme umožnit jak volat funkce tak metody. Předání parametrů se děje pomocí tuple, to proto, abysme se nemuseli trápit s předáváním variabilního počtu parametrů.

poznámky
  • Objekt předáváme jako ukazatel. Do šablony lze totiž dodat i chytrý ukazatel, který bude předán jako instance.
  • Parametry můžeme předat přímo (pak se kopírují) nebo jako ukazatel (pak se kopíruje ukazatel). Nelze předat referenci.
  • I když typy a počet parametrů uvádíme v šabloně, lze si dovolit nekonzistenci. Například můžeme požadovat jiný návratový typ, než specifikovaná funkce vrací.Pokud je konverze možná, překladačí automaticky zařídí. Lze také použít jiný počet parametrů tuple, pokud například některé parametry mají definovanou výchozí hodnotu. Jesliže není možné nekonzistenci ošetřit, překladač kód prostě nepřeloží.
actions2.zip Zdrojové soubory, obsahuje i tuples2
vytvořeno: 1.11.2007 11:00:02, změněno: 1.11.2007 11:00:40
Jsou informace v článku pro Vás užitečné?
  • ()
  • ()
  • ()
  • ()
  • ()
Nick nebo OpenID
Vzkaz
 
9.6.2014 21:42:15

wuupypwp

Very nice site!
9.6.2014 21:42:06

wuupypwp

Very nice site! cheap goods http://oieypxa2.com/kyaoqk/4.html
7.6.2014 09:11:45

wuupypwp

Very nice site!
7.6.2014 09:09:00

wuupypwp

Very nice site! cheap goods http://apxoiey2.com/qovqqt/4.html
6.6.2014 02:21:44

wuupypwp

Very nice site!
6.6.2014 02:21:32

wuupypwp

Very nice site! cheap goods http://ypxoiea2.com/ovyaoov/4.html
4.6.2014 19:56:08

wuupypwp

Very nice site!
4.6.2014 19:56:01

wuupypwp

Very nice site! cheap goods http://opeyixa2.com/qvovqqa/4.html
3.6.2014 13:27:03

wuupypwp

Very nice site!
3.6.2014 13:26:59

wuupypwp

Very nice site! cheap goods http://oieypxa2.com/oryaoor/4.html
2.6.2014 06:50:16

wuupypwp

Very nice site!
2.6.2014 06:49:57

wuupypwp

Very nice site! cheap goods http://opeyixa2.com/rvqsrrx/4.html
1.6.2014 15:23:12

yetperue

This actually answered my drawback, thank you! gfcdgeadeeac

Podobné články

C++ - Akce a Zpráva jako objekt

Akcí nazývám obyčejné volání funkce, zprávou pak volání metody objektu (jak je chápáno podle OOP). Lze vůbec volání čehokoliv reprezentovat jako objekt? A k čemu je to vlastně dobré?

Distributor - vaše objekty budou o svém okolí vědět vše

Největším problémem většiny UI /ale i ne-IU/ aplikací, které potkávám, je špatná nebo vůbec nevyřešená komunikace mezi důležitými objekty. Přitom stačí málo, obstarat si distributora.

Multithreading v C++ (ve Win32) III - OOP a vlákna

Pokračování dokumentace k Multithreading v C++ (ve Win32) - Tentokrát si povíme něco o tom jak začlenit vlákna do OOP

Šablony a kvalifikátor const - Jak správně konstruovat šablony s ukazatelem?

Chytrý ukazatel nebo pole? Vždy se jedná o šablonu, která obsahuje ukazatel na T. Přitom je třeba postihnout chování const

Efektivní alokátor malých objektů II

Pokračování seriálu Efektivní alokátor malých objektů I
Reklama: