V této části budou zveřejněny vaše dotazy i s naší odpovědí. Tak si budou moci odpověď přečíst všichni zájemci a ne pouze tazatel. Dotazy ke Kurzu C/C++ posílejte na email mého kolegy: mrandrew@atlas.cz a dotazy ke kurzu o DirectX posílejte na můj email: jiri.formanek@centrum.cz.
Pro větší přehlednost jsem rozdělil tuto sekci do více částí:
Obecné otázky
Dotazy k C++
Dotazy k DirectX
Krátké příklady
Obecné otázky týkající se programování
Je lepší Microsoft Visual C++ nebo Borland C++?
Osobně bych Vám doporučoval Visual C++, ale je to také věc vkusu. Pokud nemáte nic proti Microsoftu tak jděte do Visual C++, v opačném případě do Borlandu, který sice není špatný, ale podle mého názoru se VC++ nevyrovná. Microsoft má určitě lepší podporu nebo spíš reklamu:)
Lze změnit nastavení již rozpracovaného projektu na statické linkovaní MFC, aniž bych musel projekt znovu zavádět?
Samozřejmě. V menu Project zvolte položku Settings. Tam hned na první kartě najdete způsob linkovaní. Dávejte si ale pozor na to, že konfigurace projektu je rozdělena pro Release a Debug režim. Musíte ji nastavit nejlépe pro oba režimy, ale hlavně pro Release, protože tuto verzi pak distribuujete.
Mám nějakou třídu (například CMujEdit zděděný od CEdit) a mám ji zobrazenu v panelu ClassView. Občas se stane následující věc, které nerozumím: přidám třídě pomocí položky kontextoveho menu "Add Windows Message Handler" nějakou oblužnou funkci, pak se mi nelíbí co dělá a já ji chci odstranit. Pokud ji smažu ručně přímo v kódu, stejně jako odkaz na ní v mapě zpráv a v hlavičkovém souboru, je vše v pořádku. Pokud však kliknu v ClassView u příslušné metody na Delete a potvrdím, že se mají odkazy smazat a tělo metody zakomentovat, pak se někdy stane, že mi celá třída zmizí z ClassView a zpět se mi objeví teprve poté, co pomoci ClassWizardu znovu přidám smazanou metodu. Když ji následně vymažu "ručně", je vše v pořádku. Čím to je způsobeno?
ClassView není dokonalé. Pokud vymažete kousek klíčového slova "class", tak třída z ClassView zmizí a to je v pořádku, protože vývojové prostředí tuto třídu nenajde, ale občas se stane, že třída zmizí při normalní operaci s třídou jako je například přidávání a mazání funkcí. Toto je chyba samotného vývojového prostředí a ani nejnovější SP (Service Pack) tuto chybu neopravuje. Pokud se vám stane, že třída zmizí, pokuste se vratit krok, po kterém třída zmizela a posléze ho proveďte znovu. Pokud nejde krok vrátit, musíte buďto čekat až se jednoho krásneho dne třída znovu objeví nebo by mělo stačit vyjmout a zase přidat hlavičkový i implementační soubor, ve kterém je třída. Zkuste restartovat VC++ i cely počítač a poslední možnost je, že vymažete soubory s příponami .ncb a .opt v adresáři vašeho projektu. To jsou soubory, ve kterých je uložena právě struktura ClassView a vy tak přinutíte VC++, aby ji znovu vytvořilo.
Existuje nějaké freeware vývojové prostředí pro jazyk C/C++ a kde jej mohu získat?
Ano, existuje Dev-C++ a stáhnout si ho můžete na této adrese: www.bloodshed.nu. Nové Dev-C++ by mělo být k dispozici na ChipCD.
Nahoru
Dotazy k C++
Co je to ukazatel?
Ukazatel je druh proměnné, jejíž hodnota je adresou v paměti. Pomoci ukazatelů se dá dělat mnoho věcí, které však při špatném použití mohou vest k chybám v programu. Ukazatele se např. používají pro dynamickou alokaci paměti (tedy přímo za běhu programu). Předáni parametru pomoci ukazatele má za následek, ze se kopíruje jen 4bajtova adresa v paměti a nemusí se kopírovat cely objekt (pole, třída), který může být velice rozsáhlý. Ukazatele se také používají k předávání parametru odkazem, kdy můžeme uvnitř funkce změnit předaný parametr, což jinak není možné.
Jak mohu objektu CStatic změnit ikonu za běhu programu?
Třída CStatic obsahuje členskou funkci SetBitmap(), kterou lze změnit zobrazovaný obrázek.
Chtěl by jsem se Vás zeptat jak se dá v novém VC++ .NET napsat starý dobrý .exe program?
Všechny typy projektů z verze 6.0 najdete i ve verzi .NET. Problém je, že některé volby jsou trochu zastrčené. Když vytváříte nový projekt ve Visual C++.NET, můžete si vybrat pouze Win32 Application a teprve na dialogu Wizardu vybíráte typ aplikace (.exe, .dll, konzole). Pokud vytváříte MFC aplikaci, máte na výběr z několika možností (zde je to stejné jako ve verzi 6.0): MFC EXE a MFC DLL.
Jak převedu řetězec na číslo?
V knihovnách C++ existuje řada funkcí určené ke konverzi řetězců na číselné typy a naopak. Funkce atoi() převede vstupní řetězec typu char na celočíselnou hodnotu typu int. Funkce rozezná číslo se znaménkem, i když jsou před samotným číslem mezery tj. řetězec " -9824" je převeden na číslo -9824 atd. Kromě této funkce můžete použít atof() pro převod na typ double a atol() na převod na typ long. Pokud použijete funkci atof() nemusí být v řetězci před desetinnou tečkou žádné číslo tj. ".124" se převede na číslo 0.124. Dále můžete použít formát "1,05e-34", který se převede na hodnotu redukované Planckovy konstanty 1,05.10^-34. Bližší informace najdete v nápovědě MSDN.
Pokud používáte třídu CString, lze použít výše uvedené funkce konverzí na char.
Jaký je rozdíl mezi cout a printf()?
Ve VC++ je možné používat obojí, cout i printf(). Osobně mám radši printf(), protože umožňuje lepší formátování – kratší a přehlednější, ale jinak je to zcela na Vás.
Mohl byste mi vysvětlit rozdíl mezi ukazatelem a normální proměnnou? Proč některé funkce chtějí jako parametry ukazatele a jiné normální proměnnou?
Všimněte si, že např. funkce SelectObject() bere jako parametr ukazatel na objekt. Když se funkci předává parametr hodnotou (to znamená jako normální proměnnou bez hvězdičky), udělá se kopie předávaného objektu na stacku. Když se jedná o objekt, musí se udělat kompletní kopie, všechny proměnné! Představte si, že objekt bude mít 20 proměnných a navíc může obsahovat další objekty – to jistě uznáte, že je značně neefektivní, když pak tuto kopii stejně zahodíte. Mnohem lepší je, když předáte pouze ukazatel. Takže obecně platí, že když předáváte objekty je lepší používat ukazatele, i když nechcete objekt uvnitř funkce měnit. Naopak u běžných typů se předává hodnota, samozřejmě pokud chcete hodnotu proměnné ve funkci měnit, musíte předat buď ukazatel nebo referenci.
Je lepší Java nebo C++, a v čem?
Nedá se říci, jestli je lepší Java nebo C++. Za prvé, každý jazyk má své přednosti a své nevýhody. Za druhé se jedná o dva různé typy programovacích jazyků. I když je syntaxe velice podobná, C++ je jazyk kompilovaný tzn. že program se jednou přeloží a pak už se jen spouští. Ale Java je jazyk interpretovaný tzn. že se kód překládá při každém spuštění. Proto také C++ nemá svůj skriptovací jazyk (známe JavaScript, VBScript, ale C++Script nikoliv:). Takže by se dalo říci, že program v C++ bude vždy rychlejší než stejný program v Javě, ale také to záleží na mnoha dalších okolnostech.
Používá se v C++ v deklaraci proměnné slovo var, co to var znamená?
Nepoužívá. Klíčové slovo var se používá v Pascalu k deklaraci proměnných a k předávání parametrů funkcím odkazem. Jinak var je zřejmě od slova variable, což je proměnná.
Na základě vašeho kurzu jsem se začal učit programovací jazyk C, za použití knihy "Učebnice jazyka C 1.". Mám však problém: vždy když zkompiluji svůj program, ten se zpustí,ale po provedení všech příkazů se ihned ukončí a já nejsem schopen zkontrolovat správnost výpočtů na obrazovce. Po zkušenostech s Pascalem jsem hledal v knize nějaký příkaz podobný READKEY, ale nic takového jsem nenašel. Má jazyk C nějaký podobný příkaz? Nebo je chyba v mém kompileru?
Chyba to není. Program prostě skončí a výstupní okno se zavře. Pokud je výpočet programu rychlý, člověk postřehne jen probliknutí. Úplný ekvivalent funkci READKEY z Pascalu v C nenajdete, ale můžete použít funkci getchar(), která funguje podobně (navíc vrací ordinální číslo stisknutého znaku). Abyste mohli tuto funkci použít, musíte vložit hlavičkový soubor stdio.h.
Bude plynulý přechod z C++ na C#?
Snad ano. C# má být něco mezi Visual Basicem a Visual C++, takže prostředí bude zřejmě "přátelštější", ale stále se bude používat jazyk C++. Nyní s odstupem času můžu tento dotaz doplnit. O C# se říká, že je spojením toho nejlepšího z jazyků C++, Visual Basic a Java. Skutečně, když se podíváte na syntaxi, tak je velice podobná Javě a přesto nejde o interpretovaný jazyk. C# je zcela objektově orientovaný jazyk určený pro novou platformu .NET. Pro toho, kdo se učí C++ bude přechod na C# velice rychlý.
Nahoru
Dotazy k DirectX
Snažím se vykreslit nějaké polygony, ale nic není vidět? Jak mám postupovat v tomto případě, když si myslím, že vše mam nastavené správně?
Za prvé je třeba zjistit, jak je na tom osvětlení scény. Často se stává, že není nic vidět jenom kvuli tomu, že je prostě tma. Takže pokud používáte světlo (nastavení pomocí SetRenderState()) je třeba mít nějaké světlo vytvořené a také mít správné normálové vektory. Můžete si pomoci hodnotou D3DRS_AMBIENT v metodě SetRenderState(), čímž nastavíte globální osvětlení scény, takže pak uvidíte i neviditelné. Za druhé zjistěte, zdali máte správné pořadí vertexů (nebo indexů) v bufferu. Musí být po směru hodinových ručiček! Tento test lze vypnout hodnotou D3DRS_CULLMODE v SetRenderState(), nastavíte-li hodnotu parametru D3DCULL_NONE, pak jsou vidět i vertexy s opačným pořadím vertexů.
Jak kreslit přímo do povrchu DD?
Objekt povrchu má metodu Lock(), která vrací ukazatel na vlastní pole bufferu! Podrobné informace najdete v nápovedě MSDN. Poté co zavoláte Lock() můžete pomocí uvedeného ukazatele přistupovat přímo do paměti. Nakonec je třeba zavolat metodu Unlock().
Chtěl bych se zeptat, jakým způsobem naprogramovat v DirectX třeba 2D morphing - plynulý přechod mezi dvěmi bitmapami. Tipuju že se kreslí do nějaké offscreen plochy. Zajímá mě jak se tam kreslí? Pokud to lze přímým přístupem jako při zápisu do paměti, tak pak se chci zeptat jak a jaký formát má ta off-screen plocha.
Do jiných povrchů (i do offscreen) kreslíte úplně stejně jako například do back bufferu. Jen jako cílový buffer vyberete váš offscreen buffer. Plynulý přechod mě napadá jen pomocí aplha blendingu coz je ovšem v DD dost velký problem (vlastní DD ho ani nepodporuje). Našel jsem nějakou knihovnu kde to šlo, ale nebylo to zcela ideálni (dost pomalé). Mnohem jednoduší je v tomto případě použít Direct3D. V DD byste leda mohl použít nějaký algoritmus, který aplikujete na každý pixel výsledného povrchu (jako zdrojove pixely budou sloužit pixely z tech dvou bitmap a nějaký integer, jako stupeň přechodu). Tento způsob bude ale velmi pomaly:(
Právě jsem objevil vaši učebnici DirectX, a líbí se mi, ale já programuji v Borland C+ + Builder a tak jsem se chtěl zeptat, jestli by mi uvedené příklady fungovali a celkově o kompatibilitě kurzu.
Dále jsem se hctěl zeptat, jaký je rozdíl mezi Visual C++ a Borland C++ Builder a který z nich je lepší a taky používanější.
Obávám se, ze v mých příkladech využívám MFC a tam kde tomu tak je, bude áas Borland bezradný:( Jinak DD jako takové by snad měl nějak podporovat, ale nejsem si jistý neboť osobne programuji v MSVC, kde má DX velkou podporu v podobe SDK a jinych aplikací. Nevím to přesně, ale myslím, že se více používá MSVC než Borland, neboť jak jsem říkal má mnohem větši podporu (například MFC). Borland má sice také vlastní knihovny pro Windows, ale urcite nebudou obsahovat tolik věcí. Můj názor je: Borland na programovani v céčku ano, ale na programovani ve Windows je lepší MSVC. Kurz C++ by měl být kompatibilni s vaším prostředím.
Co je to sprite?
Odpověď byste jistě našli v některém kurzu DirectX. Sprite je z anglického překladu něco jako duch:-) Sprite je vlastně vykreslovaný obrázek. Sprite je většinou vytvořen z bitmapy, kterou načtete z externího souboru. Pokud budete mít pohybující se letadlo, právě letadlo bude sprite. Za sprite můžeme považovat například tlačítko menu nebo kurzor myši.
Jak zakomponovat zvuk do stávajících projektu DirectX?
Asi nejlepším řešením je použít další komponentu DirectX a tou je DirectMusic. Tato komponenta umožňuje, jak přehrávání hudby, tak i samostatných zvuků. DirectMusic částečně nahrazuje komponentu DirectSound, který je rovněž k dispozici, ale řekl bych, že s DirectMusic se lépe pracuje. Mám v plánu udělat malý kurz DirectMusic, kde vysvětlím základy, abyste mohli svou aplikaci ozvučit. Nebude to ovšem nic podrobného.V příštím díle DirectX se budu tomuto tématu věnovat.
Poznámka k jiným verzím Visual C++ a DirectX SDK.
Praktickým zkoušením jsem zjistil, že s novým DX SDK 8.0 pracuje pouze Visual C++ 6.0 a vyšší. Na nižších verzích nelze projekty z kurzů zkompilovat kvůli zřejmé nekompatibilitě. Proto pokud vlastníte verzi 4.0 nebo 5.0 nemůžete používat DirectX 8.0. DirectX SDK 8.0 vyšlo na ChipCD vydání 11/01.
Existuje česky psaná kniha o DirectX?
Bohužel jsem o takové publikaci neslyšel. V angličtině je takových knih několik (viz. www.microsoft.com).
Bude nejaky seriál o DirectShow?
Nebude. Po DirectDraw bych chtěl pokračovat komponentou DirectInput a pak ještě nevím, ale DirectShow to nebude.
Je možné vytváření off-screen surfaces větších nežli je velikost primary surface?
Podle dokumentace k DirectDraw je to od verze 5.0 možné, ovšem za následujících podmínek. Pro umístění do video paměti karty je nutné ověřit pomocí metody rozhraní DirectDraw GetCaps() flag DDCAPS2_WIDESURFACES, který se nachází v členské proměnné dwCaps2 první struktury DDCAPS předané metodě GetCaps(). V případě vytvoření extrémně velkého surface se však může stát, že se vytvoření neprovede, ačkoliv ovladač výše uvedený flag uvádí. V tom případě je vrácen chybový kód DDERR_INVALIDPARAMS. Tyto tzv. široké surfaces (wide surfaces) jsou vždy podporovány v systémové paměti. Ve verzích starších je velikost off-screen surface omezena velikostí primárního surface.
Nahoru
Krátké příklady
2. Nevíte, jak se dá v C++ vytvořit dynamicky alokované pole ukazatelů na int?
Víme. Stačí použít pointer na pointer na integer. Nejprve vytvoříte pole ukazatelů na integer, potom přes ukazatele v tomto poli vytvořite pole integeru. Srozumitelnější bude spíš ukázka:
#include "stdafx.h"
#include <stdio.h>
int **pp_pole;
typedef int *PINT; int main(int argc, char* argv[])
{
pp_pole = NULL;
pp_pole = new PINT[10]; pp_pole[0] = new int[1];
pp_pole[1] = new int[2];
pp_pole[2] = new int[4]; pp_pole[0][0] = 5;
pp_pole[1][0] = 6;
pp_pole[1][1] = 7;
pp_pole[2][0] = 8;
// atd.
printf("V poli jsou:\n%u\n%u %u\n", pp_pole[0][0], pp_pole[1][0], pp_pole[1][1]);
return 0;
}
1. Program pro převod čísla z desítkové soustavy do binární
1. Trocha teorie
Vezmeme desítkové číslo a stále ho celočíselně dělíme dvěma, zbytek po tomto dělení sepíšete a pak odspoda přečtete číslo vyjádřené ve dvojkové soustavě. Tedy například pro 157:
Operace Výsledek |
Zbytek |
157 : 2 78 |
1 |
78 : 2 39 |
0 |
39 : 2 19 |
1 |
19 : 2 9 |
1 |
9 : 2 4 |
1 |
4 : 2 2 |
0 |
2 : 2 1 |
0 |
1 : 2 0 |
1 |
A přečteme zespoda. Tedy: (157)dec = (10011101)bin.
2. Praxe
Proměnné:
length je délka binárního čísla, můžete ale zvolit pevně.
retezec je již alokované pole znaku o dostatečné velikosti (max. počet znaku bin. čísla + 1 znak na ukončovací \0) dělíme bitovým posunem, kdy prostě zahodíme nejméně významný bit a tím se číslo vydělí dvěma. Výsledný řetězec je vytvářen od konce.
Vlastní program:
if(0 == cislo) // osetrime 0
{
retezec[length - 2] = '0';
}
else
{
short index = length-1;
while(cislo > 1)
{
retezec[--index] = (char)('0' + (cislo % 2));// zbytek dame do spravne pozice
cislo >>= 1; // vydelime dvema (bitovy posun)
}
retezec[--index] = '1';
}
Nahoru |