Programmeren in C++/Inleiding: verschil tussen versies

Verwijderde inhoud Toegevoegde inhoud
Erwin (overleg | bijdragen)
Revert: onduidelijk
Regel 11:
We gaan er op dit moment vanuit dat je al een klein beetje ervaring met C hebt. Dit hoeft niet veel te zijn, maar het programma "Hello World" moet je bekend zijn.
 
=== Headers ===
{code}#include <iostream>
Een eerste verschil met C is dat de zogenaamde header-bestanden geen extensie meer hebben:<br />
 
'''C'''
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#include <stdio.h>
</source>}}
 
'''C++'''
{{code
|Taal= C++
|Titel=
|Code=
<source lang=cpp>
#include <iostream>
</source>}}
 
Een volgend verschil is dat er zogenaamde ''naamruimten'' (namespaces) worden gebruikt; dit om conflicten te voorkomen. De standaard header-bestanden gebruiken alle de namespace "std" (standard). Om deze namespace voor het gehele document te laten gelden, kun je "using namespace std;" gebruiken:
 
{{code
|Taal= C++
|Titel=
|Code=
<source lang=cpp>
#include <iostream>
using namespace std;
</source>}}
De oude C-headers kunnen in C++ echter wel nog gebruikt worden.<br />
Veel standaard C-headers zijn geconverteerd naar C++.<br />
Ze krijgen dan geen extensie meer, hebben een c voor hun naam gekregen en gebruiken naamruimten.<br />
Bijvoorbeeld "stdio.h" wordt "cstdio".
 
=== Functies versus objecten ===
Een van de grootste verschillen - zoniet het grootste - tussen C en C++ is dat er objecten i.p.v. functies kunnen worden gebruikt.
Het klinkt moeilijker dan het is, kijk maar...
 
Het C-programma "Hello World":
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#include <stdio.h>
 
/* Print Hello World op het scherm */
main()
{
printf("Hello World!\n");
}
</source>}}
Het C++-programma "Hello World":
{{code
|Taal= C++
|Titel=
|Code=<source lang=cpp>
#include <iostream>
using namespace std;
 
// Print Hello World op het scherm.
 
// In C++ krijgen functies een type mee, dit is meestal void of int.
int main()
Regel 23 ⟶ 82:
// cout plaatst de uitvoer vervolgens op het scherm.
cout << "Hello World" << endl;
 
// dit betekent: programma afgesloten zonder problemen
return 0;
}
</source>}}
{code}
 
Een tweede versie van het "Hello World" programma maakt gebruik van een "Begroeter"-object, een instantie van de klasse "Begroeter":
 
{{code
Regel 33 ⟶ 94:
|Titel=
|Code=<source lang=cpp>
// Gebruik de iostream header en de string header
#include <iostream>
#include <string>
using std::cout; // Wanneer we 'cout' of 'endl' gebruiken refereren we
using std::endl; // naar deze uit de naamruimte 'std'
using std::string;
 
// Definitie van de klasse "Begroeter".
class Begroeter{
protected: // beschermde onderdelen, enkel in sommige gevallen toegankelijk in de klasse zelf of van overal toegankelijk.
string begroeting;
 
private:
#include "main.h"
// Privaat toegankelijke onderdelen, enkel toegankelijk
#include <base/code.h>
// in de klasse zelf.
string begroeting;
public:
// Publieke toegankelijk onderdelen, van overal toegankelijk.
 
// Default constructor maakt een nieuwe instantie van
CConfig Config;
// deze klasse aan.
vector<CBitmap> Bitmaps;
Begroeter(){
map<IDirectDrawSurface7*,map<RECT,void*> > pLockedSurfaces;
begroeting = "Hello World";
 
bool operator<(const RECT& RectA,const RECT& RectB)
{
return RectA.bottom+RectA.top+RectA.left+RectA.right<RectB.bottom+RectB.top+RectB.left+RectB.right;
}
 
void Clip(const int& iMin, const int& iMax, int*const pi)
{
if(*pi<iMin)
{
*pi=iMin;
}
else if(*pi>iMax)
{
*pi=iMax;
}
}
 
// De zegHallo memberfunction, deze voert de begroeting uit.
void Clip(const RECT& Rect, int*const piX, int*const piY)
void zegHallo(){
{
cout << begroeting << endl;
Clip(Rect.left,Rect.right,piX);
Clip(Rect.top,Rect.bottom,piY);
}
 
void Clean(unsigned char*const pcData,
const DDPIXELFORMAT& PixelFormat,
const unsigned int& iPitch,
const unsigned int& iWidth,
const unsigned int& iHeight,
const unsigned int& iMiddleX,
const unsigned int& iMiddleY)
{
static clock_t LastRandSeedUpdated=0;
if(clock()-LastRandSeedUpdated>CLOCKS_PER_SEC/3)
{
LastRandSeedUpdated=clock();
}
};
srand(LastRandSeedUpdated);
 
int main(){
if(Config.m_Type==CConfig::MandelbrotSet)
// Maakt een nieuwe klasse aan en roept de default
{
// constructor op.
float afColorMultiplier[3];
Begroeter groeter;
for(unsigned char c=0;c<3;++c)
// Roep de lidfunctie 'zegHallo()' op.
{
groeter.zegHallo();
afColorMultiplier[c]=
// Alles was ok, geef 0 terug.
(static_cast<float>(50+rand()%150)*static_cast<float>(rand()%1000)*255.0f)/(999.0f*500.0f);
return 0;
}
 
for(unsigned int iY=0;iY<iHeight;++iY)
{
float fImg=Config.m_fIm-Config.m_fHeight/2+
static_cast<float>(iY)*Config.m_fHeight/static_cast<float>(iHeight);
for(unsigned int iX=0;iX<iWidth;++iX)
{
float fReal=Config.m_fRe-Config.m_fWidth/2+
static_cast<float>(iX)*Config.m_fWidth/static_cast<float>(iWidth);
 
float fLoopReal=fReal;
float fLoopImg=fImg;
bool bInside = true;
unsigned int iIteration;
for(iIteration=0;iIteration<500;++iIteration)
{
float fLoopRealSquared = fLoopReal*fLoopReal;
float fLoopImgSquared = fLoopImg*fLoopImg;
if(fLoopRealSquared+fLoopImgSquared>4)
{
bInside = false;
break;
}
 
fLoopImg=2*fLoopReal*fLoopImg+fImg;
fLoopReal=fLoopRealSquared-fLoopImgSquared+fReal;
}
 
if(bInside)
{
SetPixel(&pcData[iY*iPitch+iX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
0,
0,
0);
}
else
{
SetPixel(&pcData[iY*iPitch+iX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
static_cast<unsigned char>(static_cast<float>(iIteration)*afColorMultiplier[0]),
static_cast<unsigned char>(static_cast<float>(iIteration)*afColorMultiplier[1]),
static_cast<unsigned char>(static_cast<float>(iIteration)*afColorMultiplier[2]));
}
}
}
return;
}
else if(Config.m_Type==CConfig::RandomPixelColors)
{
for(unsigned int iY=0;iY<iHeight;++iY)
{
for(unsigned int iX=0;iX<iWidth*PixelFormat.dwRGBBitCount/8;++iX)
{
pcData[iY*iPitch+iX]=static_cast<unsigned char>(rand()%256);
}
}
return;
}
else if(Config.m_Type==CConfig::GrayNoise)
{
for(unsigned int iY=0;iY<iHeight;++iY)
{
for(unsigned int iX=0;iX<iWidth;++iX)
{
unsigned char cRGB=static_cast<unsigned char>(rand()%256);
SetPixel(&pcData[iY*iPitch+iX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
cRGB,
cRGB,
cRGB);
}
}
return;
}
 
if(Config.m_PictureType==CConfig::Center)
{
for(unsigned int iY=0;iY<iHeight;++iY)
{
for(unsigned int iX=0;iX<iWidth;++iX)
{
SetPixel(&pcData[iY*iPitch+iX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
Config.m_acBackgroundColor[0],
Config.m_acBackgroundColor[1],
Config.m_acBackgroundColor[2]);
}
}
 
CBitmap& Bitmap=Bitmaps[rand()%Bitmaps.size()];
int iBitmapX=iMiddleX-Bitmap.GetWidth()/2;
int iBitmapX2=iMiddleX+Bitmap.GetWidth()/2;
Clip(0, iWidth,&iBitmapX);
Clip(0, iWidth,&iBitmapX2);
 
int iBitmapY=iMiddleY-Bitmap.GetHeight()/2;
int iBitmapY2=iMiddleY+Bitmap.GetHeight()/2;
Clip(0, iHeight,&iBitmapY);
Clip(0, iHeight,&iBitmapY2);
 
Bitmap.Copy(&pcData[iBitmapY*iPitch+iBitmapX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
iPitch,
iBitmapX-(iMiddleX-Bitmap.GetWidth()/2),
iBitmapY-(iMiddleY-Bitmap.GetHeight()/2),
iBitmapX2-iBitmapX,
iBitmapY2-iBitmapY);
return;
}
 
CBitmap& Bitmap=Bitmaps[rand()%Bitmaps.size()];
 
int iX=iMiddleX-Bitmap.GetWidth()/2;
while(iX>0)
{
iX-=Bitmap.GetWidth();
}
for(;iX<static_cast<int>(iWidth);iX+=Bitmap.GetWidth())
{
int iY=iMiddleY-Bitmap.GetHeight()/2;
while(iY>0)
{
iY-=Bitmap.GetHeight();
}
for(;iY<static_cast<int>(iHeight);iY+=Bitmap.GetHeight())
{
if(Config.m_PictureType==CConfig::Collage)
{
Bitmap=Bitmaps[rand()%Bitmaps.size()];
}
 
int iRealX=iX;
int iRealX2=iX+Bitmap.GetWidth();
Clip(0, iWidth,&iRealX);
Clip(0, iWidth,&iRealX2);
 
int iRealY=iY;
int iRealY2=iY+Bitmap.GetHeight();
Clip(0, iHeight,&iRealY);
Clip(0, iHeight,&iRealY2);
Bitmap.Copy(&pcData[iRealY*iPitch+iRealX*PixelFormat.dwRGBBitCount/8],
PixelFormat,
iPitch,
iRealX-iX,
iRealY-iY,
iRealX2-iRealX,
iRealY2-iRealY);
}
}
}
</source>}}
 
Het Begroeter-object wordt gedefinieerd door het class- of het struct-keyword (class is nieuw
RECT GetRect(const RECT*const pRect)
tov C, en struct kan hier nu ook memberfunctions bevatten en is dus uitgebreid tegenover C). Zoals
{
opvalt, is de klassedefinitie in twee gesplitst door de woorden "private" en "public". Na "private"
if(pRect)
komen alle lidfuncties en variabelen die eigen zijn aan de klasse en niet van buitenaf
{
geraadpleegd of gewijzigd kunnen worden.
return *pRect;
}
 
Voorbeelden:
RECT Result;
*Vanuit de main functie kan men de 'begroeting' string niet wijzigen of opvragen (adhv groeter.begroeting).
Result.top=numeric_limits<long>::max();
*Indien de zegHallo() lidfunctie, die nu in het "public" deel staat en dus publiek toegankelijk is (adhv groeter.zegHallo() ), verplaatst zou worden naar het "private" gedeelte, zou de oproep falen.<br />
Result.bottom=numeric_limits<long>::max();
Result.right=numeric_limits<long>::max();
Result.left=numeric_limits<long>::max();
return Result;
}
 
In het "private" gedeelte zit enkel de begroetingsstring (C++ ondersteunt string objecten welke makkelijker te hanteren zijn dan de char * in C, char * is wel nog steeds bruikbaar). Deze begroetingsstring wordt ingesteld door
typedef HRESULT (__stdcall *pUnlock_t)(IDirectDrawSurface7*, LPRECT);
de defaultconstructor in het publieke gedeelte van de klasse. Een constructor is een lidfunctie
pUnlock_t pUnlockDetour;
die geen returntype heeft en als naam, de naam van het object heeft. Deze wordt aangeroepen indien
void* pUnlock;
een instantie van het object aangemaakt wordt om administratieve zaken goed te zetten (in dit
HRESULT __stdcall MyUnlock(IDirectDrawSurface7* pClass, LPRECT Arg1)
geval de private begroetingsstring). In een programma schrijven "klasseNaam identifier" roept
{
de default constructor (een constructor die geen parameters neem) impliciet aan tenzij
map<IDirectDrawSurface7*,map<RECT,void*> >::iterator pLockedSurface=pLockedSurfaces.find(pClass);
overladen constructors beschikbaar zijn en aangeroepen worden. Een uitbreiding op de klasse zou
if(pLockedSurface!=pLockedSurfaces.end())
de volgende kunnen zijn:
{
{{code
map<RECT,void*>::iterator pLockedRect=pLockedSurface->second.find(GetRect(Arg1));
|Taal= C++
if(pLockedRect!=pLockedSurface->second.end())
|Titel=
{
|Code=
delete[] pLockedRect->second;
<source lang=cpp>
pLockedSurface->second.erase(pLockedRect);
class Begroeter{
}
....
}
public:
 
...
return pUnlockDetour(pClass,Arg1);
Begroeter(string s){
begroeting = s;
}
...
};
</source>
}}
Hier definieren we een tweede constructor welke de begroeting wijzigt, wanneer we nu het
hoofdprogramma zouden wijzigen tot:
{{code
|Taal= C++
|Titel=
|Code=
<source lang=cpp>
int main(){
// Maakt een nieuwe klasse aan en roept de default
// constructor op.
Begroeter groeter("Kiekeboe");
// Roep de lidfunctie 'zegHallo()' op.
groeter.zegHallo();
// Alles was ok, geef 0 terug.
return 0;
}
</source>}}
Dan roepen we de tweede constructor op die een string als argument neemt. De laatste
publieke functie in de klasse is de zegHallo() lidfunctie welke de begroeting uitschrijft
naar standaard uitvoer.
 
<!-- --------------- Hieronder onderhoudsmeldingen -------------- -->
typedef HRESULT (__stdcall *pLock_t)(IDirectDrawSurface7*, LPRECT,LPDDSURFACEDESC2,DWORD,HANDLE);
{{sub}}{{GFDL-oud}}
pLock_t pLockDetour;
void* pLock;
HRESULT __stdcall MyLock(IDirectDrawSurface7* pClass, LPRECT Arg1,LPDDSURFACEDESC2 Arg2,DWORD Arg3,HANDLE Arg4)
{
HRESULT Result=pLockDetour(pClass,Arg1,Arg2,Arg3,Arg4);
if(FAILED(Result))
{
return Result;
}
 
HWND Wnd=GetForegroundWindow();
if(!Wnd)
{
return Result;
}
 
RECT WindowRect;
if(!GetClientRect(Wnd,&WindowRect))
{
return Result;
}
POINT Point;
Point.x=WindowRect.left;
Point.y=WindowRect.top;
if(!ClientToScreen(Wnd,&Point))
{
return Result;
}
 
int iX=Point.x;
int iY=Point.y;
int iX2=Point.x+WindowRect.right-WindowRect.left;
int iY2=Point.y+WindowRect.bottom-WindowRect.top;
int iMiddleX=Point.x+(WindowRect.right-WindowRect.left)/2;
int iMiddleY=Point.y+(WindowRect.bottom-WindowRect.top)/2;
 
RECT RealRect;
if(Arg1)
{
RealRect=*Arg1;
}
else
{
RealRect.left=0;
RealRect.right=Arg2->dwWidth;
RealRect.top=0;
RealRect.bottom=Arg2->dwHeight;
}
 
Clip(RealRect,&iX,&iY);
Clip(RealRect,&iX2,&iY2);
Clip(RealRect,&iMiddleX,&iMiddleY);
 
if(iX==iX2 ||
iY==iY2)
{
return Result;
}
unsigned char* pcNewData=new unsigned char[Arg2->dwHeight*Arg2->lPitch];
Clean(&pcNewData[iY*Arg2->lPitch+iX*Arg2->ddpfPixelFormat.dwRGBBitCount/8],
Arg2->ddpfPixelFormat,
Arg2->lPitch,
iX2-iX,
iY2-iY,
iMiddleX-iX,
iMiddleY-iY);
 
RECT IndexRect=GetRect(Arg1);
if(pLockedSurfaces[pClass][IndexRect])
{
delete[] pLockedSurfaces[pClass][IndexRect];
}
pLockedSurfaces[pClass][IndexRect]=pcNewData;
Arg2->lpSurface=pcNewData;
 
return Result;
}
 
BOOL APIENTRY DllMain(HMODULE Module,DWORD Reason,LPVOID)
{
if(Reason!=DLL_PROCESS_ATTACH)
{
return TRUE;
}
DisableThreadLibraryCalls(Module);
//TODO: Load the configuration into 'Config'. Use FM or a fstream!
 
if(Config.m_Type==CConfig::Picture)
{
char* pcCurrentFileName=&pConfig->m_acFileNames[0];
while(*pcCurrentFileName!='\0')
{
string sFileName;
while(*pcCurrentFileName!='\0')
{
sFileName+=*pcCurrentFileName;
++pcCurrentFileName;
}
++pcCurrentFileName;
 
CBitmap Bitmap(sFileName);
if(!Bitmap.IsValid())
{
MessageBox(NULL,
string(string("ERROR: Cannot load \"") + sFileName + "\" (Not a 24 or a 32bit BMP?)").c_str(),
"ERROR",
MB_OK|MB_ICONERROR);
return TRUE;
}
else if(Config.m_PictureType==CConfig::Collage&&
Bitmaps.size() &&
(Bitmaps[0].GetHeight()!=Bitmap.GetHeight() || Bitmaps[0].GetWidth()!=Bitmap.GetWidth()))
{
MessageBox(NULL,
"ERROR: All pictures MUST have same width and height!",
"ERROR",
MB_OK|MB_ICONERROR);
return TRUE;
}
Bitmaps.push_back(Bitmap);
}
}
 
if(!Bitmaps.size() &&
Config.m_Type==CConfig::Picture)
{
MessageBox(NULL,"ERROR: At least one image must be loaded!","ERROR",MB_OK|MB_ICONERROR);
return TRUE;
}
 
IDirectDraw7* pDirectDraw;
if(FAILED(DirectDrawCreateEx(NULL,reinterpret_cast<void**>(&pDirectDraw),IID_IDirectDraw7,NULL)) ||
FAILED(pDirectDraw->SetCooperativeLevel(NULL,DDSCL_NORMAL)))
{
MessageBox(NULL,"ERROR: Internal error...","ERROR",MB_OK|MB_ICONERROR);
return TRUE;
}
 
DDSURFACEDESC2 Desc;
ZeroMemory(&Desc,sizeof(DDSURFACEDESC2));
Desc.dwSize = sizeof(DDSURFACEDESC2);
Desc.dwFlags=DDSD_CAPS;
Desc.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
 
LPDIRECTDRAWSURFACE7 pSurface;
if(FAILED(pDirectDraw->CreateSurface(&Desc,&pSurface,NULL)))
{
MessageBox(NULL,"ERROR: Internal error...","ERROR",MB_OK|MB_ICONERROR);
 
pDirectDraw->Release();
return TRUE;
}
 
pLock=(*reinterpret_cast<void***>(pSurface))[25];
pLockDetour=reinterpret_cast<pLock_t>(
DetourFunction(reinterpret_cast<unsigned char*>(pLock),reinterpret_cast<unsigned char*>(MyLock)));
 
pUnlock=(*reinterpret_cast<void***>(pSurface))[32];
pUnlockDetour=reinterpret_cast<pUnlock_t>(
DetourFunction(reinterpret_cast<unsigned char*>(pUnlock),reinterpret_cast<unsigned char*>(MyUnlock)));
 
pSurface->Release();
pDirectDraw->Release();
 
return TRUE;
}
 
}
</source>}}
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.