Registrace nového uživatele     Návod     Kluby     Archív  Lopuchu     Lopuch.cz  

Něco navíc v zeleném?
A proč ne...

Lopuch.cz

Jméno:
Heslo:
Podpora LCD:
 
Klub C, C++ [ŽP: neomezená] (kategorie Programování) moderuje Šéf Lopuchu.
Archiv

Články

Jak bezpečně ukončit vlákno z DllMain
FastAllocPool - urychlení častých alokací a dealokací
Akce a zpráva jako objekt
Tuply v C++
Efektivní alokátor malých objektů a tady druhý a třetí díl
Šablony: Být vládce kvalifikátorů
Vracíme z funkce objekty
Základy komunikace mezi procesy (ve Windows)
Multiple Interface a Instance Factory
Multithreading v C++ (ve Win32)
  Nastavení klubu     Nastavení práv     Homepage     Anketa     Přítomní     Oblíbené     Lopuch     Kategorie  
autor: 
text: 
vyplnit a 
Help
 Titulek, text příspěvku  
Opište pozpátku následující text bez prostředního znaku: gwxugwk
[ 380 ] <Novější  <<<Nejnovější  Nejstarší>>>  Starší>  
anonym 19.7.2006 17:31  516
cau lidi, mam takovej problem, chci začít s programovíním v C++, ale nechci vrážet peníze do literatury, tudíž vás prosím jestli někdo nevíte kde by se na netu našly začátky programování v c++..moc díky
bredy 19.7.2006 07:55  515
Know How - MultipleInterfacesTen kdo programuje v Javě určité zná slovo interface. Programátor v C++ to slovo nezná, pokud ho tedy neslyšel v podobné souvislosti, ale v C++ jej jako příkaz nenalezneme. Nicméně i tam můžeme napsat, že interface je vlastně abstraktní třída, která neobsahuje implementaci žádné z funkcí, kterou deklaruje

 class IExampleIfc
 {
 public:
    virtual void fn1(...)=0;
    virtual void fn2(...)=0;
    ....
 };

(já nejčastěji označuji interface písmenem I)

Nedávno jsem řešil problem. Mám interface, který je obecným základem pro nějakou hierarchii tříd. To znamená, že existuje několik (desítek) potomků, kteří tento interface dědí a implementují jeho funkce. Potud by to nebyl žádný zádrhel. Modul o kterém mluvím je víceméně hotový a používá se v několika projektech. A tak jsem si jednoho dne sedl a řekl, že napíšu vizualizátor této struktury, tj, že si napíšu nějaký program, který vypisovat data objektů z nějaké kolekce, kde každý objekt je právě instancí třídy některého potomka.

Mno, co s tím, ideální by bylo, kdybych měl na interface funkci Draw, kterou pak budu volat na každý objekt a podle typu se ten který objekt nakreslí. Jenže na interface taková metoda není, musela by se tam dopsat. Jenže jak jsem řekl, modul je víceméně hotový a používá se v několika projektech, zasahovat do jeho základní části jen proto, abych uspokojil nároky jednoho programu je dost velká odvaha (a hloupost). Co teď s tím?

Mohl bych zjišťovat typ každého objektu a mít připravený obrovský switch, jenž by na základě typu vyvolal nějaké kreslení. Nejde to napsat lépe?

Ono by stačilo, kdyby součástí rozhraní byla funkce, která by mi umožnila vrátit něco obecného, z čeho bych poznal co mám dělat dál. Ideálně ukazatel na nějaké jiné rozhraní. Jenže to rozhraní sám modul nezná, muselo by to být nějaký univerzální rozhraní...

Teď trochu odskočíme do Windows a jeho COM+ objektů. Ti co programují v COM+ znají, že základní rozhraní (ze kterého se dědí celé COM+) se jmenuje IUnknown a má tři metody. AddRef, Release a QueryInterface. AddRef a Release nechme stranou, slouží jen k počítání referencí pro automatické uvolnění opuštěních objektu (jednoduchý GC). Zaměřme se na QueryInterface. Každý objekt COM+ tuto metodu má. Funkcí dodáme nějakou identifikaci rozhraní a výsledkem je ukazatel na to rozhraní. Už svítá?

Udělejme return k našemu problému. Jak to tedy udělat s tím Draw? Budu muset do základního rozhraní dopsat něco podobného jako QueryInterface. Na základě nějakého smluveného ID se budu moci dotázat na případná další rozhraní přístupné v objektu. Výchozí implementace přitom může vracet NULL. Budu-li tedy implementovat Draw, musím každého potomka ještě podědit a rozšířit o nějaké moje rozhraní, které bude obsahovat deklaraci Draw.


class Potomek10: IPredek
{
 // pisu jen proto, aby bylo vědět, jak potomek dědí základní rozhraní
}

class IMojeDrawRozhrani
{
  virtual void Draw(Graphics &g)=0;
}


class MujPotomek10: public Potomek10, public IMojeDrawRozhrani
{
 public:
   virtual void *QueryInterface(int id)
   {
     if (id==smluvene_id)
         return static_cast<IMojeDrawRozhrani *>(this);
     else
         return __super::QueryInterface(int id);
   }
   virtual void Draw(Graphics &g)
   {
    //malovani
   }
}

Ještě musím do základního interface doplnit ještě toto
virtual void *QueryInterface(int id) {return 0;}

Ano, rozhraní vracím jako void *. Pro konverzi na rozhraní pak musí použít reinterpret_cast Je to malý flíček na celé struktuře. Hezčí by bylo, kdyby to bylo něco obecnějšího. Kam ale chcete zobecnit rozhraní? A pomohl bych si nějak? Jediným efekt by byla změna přetypování z reinterpret_cast na static_cast. Ano, mohl bych taky použít dynamic_cast pro runtime kontrolu, zda-li objekt opravdu vrací to co chci (ale to mohu myslím teď taky - a navíc je to zbytečné, pokud by tomu tak nebylo, je to chyba kterou musím řešit na úrovni zdrojáků, né v době běhu).

Pokud budu chtít nakreslit objekt:
IPredek *p=container[x];
IMojeDrawRozhrani *r=reinterpret_cast<IMojeDrawRozhrani *>(p->QueryInterface(smluvene_id));
if (r) r->Draw(g);
else 
  DrawNeznamyObjekt(g); //objekt neznám, nemohu kreslit.


Celá operace má jednu podmínku. Má aplikace, která chce toto využít musí na počítku být schopná kontrolovat vznik objektů. Musí upravit tento vznik tak, aby vznikali rozšíření potomci (o rozhraní Draw), Znamená to pro každého potomka napsat další třídu a tu pak použít při new. Dobře napsané knihovny které například vytváří struktury při čtení z disku obsahují tzv. faktory třídy. Což jsou třídy, které pro každy typ objektu v souboru obsahují virtuální metodu, jejíž úkolem je podle typu vytvořit instanci. Aplikace pak samozřejmě tuto třídu dědí a implementuje si metody tak, aby vracely instance potomků těchto tříd.

Tak ať máme o čem mluvit....
bredy 19.7.2006 07:18  514
DRUH 5618No jo, ale co ty příklady mají dělat? Hrát nějaké hry (piškorky?, řešit sudoku?), nebo dělat něco praktického?

Podle mého názoru naučit se psát v C++ není problém, syntaxe C++ se dá naučit za pár hodin. Podívej se ale po google, určitě bys našel zajímavé programátorské problémy a jejich řešení. Začneš něčim jednoduchým (řazení, vyhledávání, stromy, grafy), pak třeba problémy prohledávání stavového prostoru (dámy na šachovnici, přelejvání kýblů. problém batohu, problém obchodního cestujícího). Ono se to nezdá, ale dobrý programátor není ten, který umí napsat krásně vypadající aplikaci se super UIčkem, která slouží jen ke konverzi MP3 na WAV a zpět (jenž stejně využívá standardní kodeky), ale ten, který umí napsat řešení nějakého obtížného problému (třeba unwrap UV souřadnic na 3D modelu), k čemuž často právě využije některý výše popsaný problém, který řešit umí.

Zaměřil bych se tedy na "domácí úlohy" tohoto typu a zkusil si něco napsat. Zkus třeba toto
druh_5618 Druh_5618 17.7.2006 12:02  513
Bredy Jakéhokoliv. Mohly by to být i typické "domácí úlohy" nebo příklady z knih.

Srovnej např.: Zadání: Konzole, jediný parametr je URL bez překlepu, soubor se uloží do aktuálního adresáře....
Versus: Kompletní zdrojáky WGETu se všemi jeho funkcemi a portovatelností.
johny_g Johny_G - Relaxační terapie pro lopušáky ZDARMA! 16.7.2006 11:07  512
Chtěl bych se pochlubit, kde se dá. Má hra Eleworia byla dnes dokončena. Píšu to sem, jelikož bych rád dodal, že je psána v C#, a že coby high level programátor si jej nemůžu vynachválit. Profík to samozřejmě musí vidět jinak ;-).
http://www.ceskehry.cz/forum/viewtopic.php?t=3783
bredy 11.7.2006 12:36  511
DRUH 5618A jakého okruhu se ty příklady mají týkat?
druh_5618 Druh_5618 11.7.2006 09:06  510
Myslím, že jedním z problémů začátečníků, je že by potřebovali příklady velice jednoduchých a přitom provozuschopných programů. Nevíte o něčem takovým?
bredy 4.7.2006 21:51  509
Tak jsem se dozvěděl, že VC++ 2005 podporuje více exception handling modelů. Lze zapnout synchronní zpracování výjimek, což znamená, že C++ bude odchytávat výjimky jen od těch funkcí, které to oznámí (v throw)

http://msdn2.microsoft.com/en-us/library/1deeycx5.aspx

Až přijedu z dovolené, podívám se na to, jakou to má režii.
bredy 2.7.2006 20:56  508
Proti tomu nic nemám. Doufejme že to vědi ostatní. A že znají význam toho slova.

(jen škoda té implementace v MSVC, něco co vzniká výjimečně sežere docela výkonu)
kdokoliv Kdokoliv Nevidím důvod dělat cokoliv bezdůvodně. - http://kkl2401.wz.cz 2.7.2006 19:39  507
Bredy [506]: Ano, vyjimecna situace, ale ne nutne chyba, to se snazim rict.
bredy 2.7.2006 19:34  506
KdokolivJenom napíšu můj názor:

No výjimka je od slova výjimečná situace. A smyslem výjimek je ošetřovat výjimky. Ale jak nás svět, a život (a zejména politika) učí, čím méně výjímek, tím lépe.

Pokud bych náhodou výjimku užíval, jako další návratovou hodnotu,
pak nejsem moc dobrý programátor. A jistě se mnou budeš souhlasit, že
vzhlídnout se v longjump spíš taky ukazuje na špatný
programátorský styl (nevím jak Céčkaři tento nástroj používají, ale
rozum mi říká, že to je něco stejně špatného, jako příkaz goto - né že by se občas nehodil)

PS: NullPointerException - ano, šlo by to takto ošetřovat. Ale zapínal bych to jen ve zvláštních situacích. Nebo bych to povolil hlásit jen tam, kde funkce má hlavičce tuto výjimku v seznamu. Protože to zase znamená dodatečnou režiji, která je špatná. Nebo chytré pointery, které mohou mít samozřejmě vlastní sadu výjimek na ošetření těchto situací... ArrayOutOfBoundsException může vyhazovat objekt simulující pole, a nemusí to být runtime exception (mluvím o C++)
kdokoliv Kdokoliv Nevidím důvod dělat cokoliv bezdůvodně. - http://kkl2401.wz.cz 2.7.2006 19:25  504
Bredy [503]: NullPointerException v C++ nastava, resp. neni problem, aby to tak nejaky prekladac neprekladal - proste pri kazde dereferenci NULLu by se vyhodila tahle vyjimka, zadnej problem. Nicmene runtimovejch vyjimek je vic, treba ArrayOutOfBoundsException (ta samozrejme opet v C++ nedava moc dobrej smysl) a asi rada dalsich, sam bych se musel kouknout do specifikace a to se mi nechce.
Ja myslim, ze Tvuj problem s vyjimkami je proste ten, ze podle Tebe vyjimka nutne znamena chybu. Dokud se nedokazes od tohoto pohledu na vec odpoutat, tak Ti nikdy vyjimky neprijdou uzitecne. Na druhou stranu Te k tomu nikdo nemuze nutit a ja jsem toho rozhodne dalek. Kazdopadne je obcas uzitecne se na vyjimku podivat proste jako na neco, co jenom nese jakousi v tu chvili uzitecnou informaci a co nemusi souviset s nejakym chybovym stavem.
bredy 2.7.2006 19:00  503
Java je řízený jazyk, takže tam jakákoliv neplatná operace znamená nějakou výjimku. Nakopak v C++ je vše co překladač přeloží platné. Takže něco jako NullPointerException a podobně tam neexistuje. Myslím, že v C++ něco jako runtimové výjimky nejsou potřeba.

Osobně si myslím, že aplikace nesmí generovat a odchytávat runtimové výjimky. Není to dobrý programátorský styl. Přijde mi divné, že si programátor odchytává výjimkou svou neschopnost najít chybu v programu.

Každé API musí definovat seznam chybových stavů a všechny tyto stavy musí pokrýt všechny chyby, které se mohou v API nastat. Protože žádný příkaz v C++ negeneruje výjimku (výjma throw), pak myslím, že runtime výjimky nejsou potřeba. Tím zmizejí neočekávané výjimky. Ostatní výjimky jsou očekávané a tedy se dají řešit v době překladu.

Mimochodem, můj názor na neočekávané výjimky... jednou jsem řekl: "pokud v programu nastane chyba, nedá se o stavu toho programu nic určitého říct a už vůbec né o stavu dat"
kdokoliv Kdokoliv Nevidím důvod dělat cokoliv bezdůvodně. - http://kkl2401.wz.cz 2.7.2006 10:23  502
Ano, jednou z vyhod Javy je to, ze uz jeji zakladni API je pomerne bohate, ale hlavne dava relativne dobre navody, jak vytvaret vlastni API, ktereho se pak ridi vyrobci 3rd party reseni. Tudiz v Jave se proste tak nejak vsechno chova docela hezky unifikovane (jakkoliv to cloveku obcas zase leze na nervy, protoze je nekdy Java proste desne ukecana) a muzes obvykle s klidnym srdcem ocekavat, ze jak interni API, tak nejake cizi bude vyhazovat nejake hezke a dobre definovane vyjimky.
Jenom bych podotknul, ze nelze uplne vsechno resit deklaraci throws, protoze existuji runtimove vyjimky, ktere muze vyhodit prakticky kazda funkce a ktere tudiz nema smysl davat do casti throws (a ktere taky neni uzivatel povinen odchytavat). Tudiz nikdy nedokazes vyjmenovat vsechny vyjimky, ktere pri volani mohou nastat, resp. v zasade dokazes, ale kdybys to mel delat a vzdy odchytavat, tak zase skoncis nekde, kdes urcite skoncit nechtel.
bredy 1.7.2006 23:49  501
Kdokolivale co kdyz je otevriSoubor cizi API funkce
Správná otázka. Mohu tě ubezpečit, že co autor to vlastní systém zabezpečení chyb. Vem si kteroukoliv third-part knihovnu a uvidíš to sám. Návratové kódy, failstate objektu, výjimky, errno, last error, atd. Třeba WinAPI používá lásterror (GetLastError). Pro MT aplikace má každý thread vlastní proměnnou lasterror, takže se thready neovlivňují. Novější WinApi (Com+) používají HRESULT, což je číslo, dost šíleně sestavené obsahující typ chyby, id chyby, kód výrobce a kód modulu. v Com+ každá funkce buď vrací nulu (Ok) nebo HRESULT, a jiný návratový hodnoty nemá. V Alias Maya se zase chyba vrací přes pointer nebo referenci na proměnnou předanou jako parametr volané funkce. Pak si musíš status zkontrolovat. A ještě ve WinApi, třeba MFC pro objekty CInternetConnection využává výjimky pro hlášení chyb připojení k internetu.

V zásadě tedy, pokud používám cizí Api, buď si napíšu wrapper (i DirectX doporučuju ten čas tomu věnovat). nebo odchytávám chyby knihovny na nejnižší možné úrovni a používám schránku chyb. Kód chyby do ní předávám bez změny s tím, že si poznačím, o jaký modul se jedná. Při chybě pak vracím false nebo failobject (nebo NULL), s tím, že nadřazený level najde důvod chyby ve schránce (vidíš, to je trochu obdoba varianty last error, s tím, že zacházení s chybou lze na všech úrovních libovolně přetěžovat.) Pokud third part knihovna vyhazuje výjimky, snažím se je všechny odchytávat na nejnižší úrovni a házet do schránky (a dále již provádět řízený návrat).

To že se v C++ často výjimky v API nepoužívají je řekl bych kvuli jejich problematické implementaci. Překladač (aspoň tedy MSVC) je stále implementuje tak, že výjimky mají dost velkou režii i když je vlastně nepoužíváš.

Tady vlastně Java má něco co ani nepotřebuje, ale hodilo by se to do C++. Povinná specifikace throw u funkcí. Zatímco Java si poradí i s výjimkami, které někdo neočekává (např. NullPointer) takže by ani seznam vyhazovaných výjimek nepotřebovala, v C++ by se to náramě hodilo. Kdyby překladač výužil znalost které volání způsobí kterou výjimku, pak by si podle mého názoru stack unwind mohl odpustit a výjimku by řešil už v době překladu. Prostě by výjimka nebyla nic, než speciální návratová hodnota z funkce, a program by jen hodnotu odtestoval a v případně pozitivního výsledku by provedl příslušnou čistící část funkce (jenž by překladač připravil už během překladu) bez nutnosti znát který objekty je nutné vyčistit (protože právě by překladač dopředu věděl, kde může nastat výjimka).

Je zajímavý, že
try{
  Object1 a;
  Object2 b;
  Volani(); //haze vyjimku
}
catch(Vyjimka e)
{
  e.VypisPopis();
}

lze dobře implementovat. jako

  Object1 a;
  Object2 b;
  if ((Vyjimka e=Volani()).JeVyjimka) {e.VypisDuvod;return false;}

V prvém případě bude kód obohacen o několik instrukcí exception handlingu, v druhém případě o jeden test a čistící části, kterou zabezpečí příkaz return - kdyby se vědělo. že Volani vyhazuje výjimku Vyjimka, nemusel by přehladač vymýšlet žádný exception handling...


[ 380 ] <Novější  <<<Nejnovější  Nejstarší>>>  Starší>  

(c) 2001-2011 Lopuch.cz   
Kontakt