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
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.
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ý.
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.
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;
}
2. 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';
}