| |
Een internet pagina voor 'C++' software ontwikkelaars.
Op deze pagina probeer ik een soort naslagwerk voor 'C++' programmeurs
te maken, in het Nederlands. Deze pagina is niet beschikbaar in de Engelse
versie, omdat er voor de Engelse taal al hele goede internet sites zijn.
(c) Hein Pragt 1998
In dit artikel probeer ik een aantal goede redenen te geven om over te stappen
op 'C++' zonder het object georiënteerd deel te gebruiken. Dit is in
mijn visie de eerste stap die 'C' programmeurs kunnen maken zonder een cultuur
schok door te maken. Object georiënteerd programmeren is namelijk een
andere denk en ontwerp wijze in plaats van alleen wat nieuwe functies. Maar
'C++' is heel goed te gebruiken zonder object georiënteerd te werken.
Toen ik 8 jaar geleden voor het eerst kennismaakte met 'C++' zei ik spottend
tegen een collega, "Alles wat in 'C++' mogelijk is, kan ik ook in standaard
'C' maken, ik zie het nut niet zo". Ik had volkomen gelijk, en vele
collega 'C' programmeurs waren het met me eens.
Het was pas twee jaar later toen ik helemaal 'om' was voor het object georiënteerd
programmeren, dat ik mij verder ging verdiepen in 'C++'. Ik ontdekte ook
dat zonder object georiënteerd programmeren de taal 'C++' een sterk
verbeterde 'C' is, en ik zal proberen uit te leggen waarom.
Inhoud opgave deel 1
De controle op variabele en functie types is heel strikt in 'C++', dit houdt
in dat als U alles heel goed moet declareren. Als U een ander type parameter
wilt gebruiken dan de gedeclareerde, of in een expressie verschillende data
types gebruikt, bent U verplicht een cast te gebruiken. Dit geld ook voor
signed en unsigned en char naar int conversie. Zo slordig als we in 'C'
kunnen zijn kan in 'C++' absoluut niet. Dit lijkt wat omslachtig maar het
zorgt ervoor dat we beter aangeven aan de compiler wat we eigelijk willen,
en voorkomt veel programmeer fouten.
Ik vind het prettig om goed door een compiler op mijn vingers gekeken te
worden, en compileer dan ook meestal op het hoogste warning niveau. Dit
is gratis controle door de compiler, en dit heeft me al redelijk wat bugs
bespaart.
Helaas is het met Microsoft nog wel eens zo dat hun eigen include files
niet zonder warning op het hoogste warning niveau gecompileerd kunnen worden.
Dit los ik dan op door rond de #include file een #pragma te gebruiken om
de warnings tijdelijk uit te zetten.
Terug naar inhoud opgave
'C++' heeft een verbeterde methode om commentaar te plaatsen. Naast de bestaande
methode door middel van /* ... */ staat C++ het ook toe, door middel van
een // dubbele slash de rest van de regel als commentaar te beschouwen.
(Dit was in de meeste ANSI compilers ook al mogelijk.) De twee commentaar
stijlen kunnen ook door elkaar gebruikt worden.
void testfunc(int i) // Dit is een commentaar tot einde regel.
{ /* Dit is oude commentaar stijl
en kan over meerdere regels lopen. */
}
Terug naar inhoud opgave
'C++' kent een verbeterde cast, in plaats van (long) var kan nu ook long(var)
geschreven worden, wat een stuk duidelijker aangeeft wat we bedoelen.
result = long(var1) * var2;
TestFunc(long(IntVar),Str);
Terug naar inhoud opgave
In 'C++' moet elke functie gedeclareerd worden voor ze gebruikt word, dit
verplicht de programmeur tot netjes declareren. Ook dit is weer extra controle
door de compiler van de programmeur. Als deze de functie anders wil aanroepen,
is hij verplicht een cast te gebruiken. (Dit was in ansi 'C' ook al aanbevolen
maar niet verplicht.)
Terug naar inhoud opgave
Binnen 'C++' word behalve de functie naam ook de parameters en de return
waarde gebruikt in de symbol table. Dit houdt in dat we dezelfde functie
met andere parameters kunnen declareren zonder iedere keer een andere naam
te bedenken. Denk hierbij aan de functies atoi() atof() atol() uit de standaard
'C' library, welke in 'C++' een functie kunnen zijn.
In 'C' zouden we het afdrukken van verschillende types zo oplossen:
void DrukafInt(int getal)
{
// Code
}
void DrukafLong(long getal)
{
// Code
}
void DrukafStr(char *str)
{
// Code
}
void TestFunc()
{
DrukafInt(10);
DrukafLong(423424L);
DrukafStr("test");
}
In 'C++' zoekt de compiler de goede functie afhankelijk van de parameters.
void Drukaf(int getal)
{
// Code
}
void Drukaf(long getal)
{
// Code
}
void Drukaf(char *str)
{
// Code
}
void TestFunc()
{
Drukaf(10);
Drukaf(423424L);
Drukaf("test");
}
Dit houdt in dat we voor alle parameter types een functie naam kunnen gebruiken.
Terug naar inhoud opgave
In 'C++' kunnen we een functie met een variabel aantal parameters aanroepen,
als we gebruik maken van default parameters.
void TestFunc(char *Str, int i = 5)
{
cout << Str << " " << i; // Druk resultaat af!
}
TestFunc("Dit is met twee parameters",10); // Dit drukt 10 af
TestFunc("Dit is met een parameter"); // Dit drukt 5 af
Terug naar inhoud opgave
In 'C++' kunnen variabelen overal gedeclareerd worden, en hun scope is het
block {} waarbinnen ze zich bevinden. In 'C' moeten declaraties vooraf gaan
aan statements, in 'C++' mag daar waar een statement toegestaan is, ook
een declaratie staan. Dit maakt het mogelijk om bijvoorbeeld binnen if
code blokken locale variabelen te gebruiken.
int TestFunc()
{
int var1; // Deze variabele is globaal voor de hele functie
// code
if (var1> 100) {
int var2; // De scope van deze variabele is dit if block
// code
} // Einde variabele var2
int var3; // Hier begint variabele var3
// code
} // Hier eindigen var1 en var3;
Terug naar inhoud opgave
In 'C++' kunnen we de loop variabele in het for statement declareren.
De scope van deze variabele is het vorige {} code block, hoewel we misschien
verwachten dat de scope de for loop zou zijn. In dit voorbeeld is
de variabele ind na de for loop ook nog te gebruiken.
void TestFunc()
{
for (int ind=0; ind < 10; ind++)
{
// code
}
}
Terug naar inhoud opgave
In 'C++' kunnen we als we een structure gedeclareerd hebben, variabelen
van dit soort zonder het woord struct declareren. Dit kon in 'C' ook wel
door middel van een typedef, maar is in 'C++' prettiger opgelost.
struct Stype {int a, int b };
Stype StructVar;
Dit geld ook voor enum en union.
enum Boolean { FALSE, TRUE };
Boolean Gereed = FALSE;
Terug naar inhoud opgave
In 'C++' maakt het keyword const een variabele een echte constante. De compiler
zal ook een foutmelding geven als de programmeur de waarde probeert te veranderen.
const int Cvar = 100;
void Test(const int index)
{
index = 5; // Hier geeft de compiler een foutmelding
}
void Test()
{
Cvar = 10; // Ook hier geeft de compiler een foutmelding
}
int Varray[Cvar]; // Dit zou in 'C' een foutmelding geven.
Terug naar inhoud opgave
Een van de belangrijkste wijzigingen in 'C++' is de vervanging van de standaard
I/O library stdio in iostream. Het gebruik van iostream is heel wat eenvoudiger
dan stdio, al is het even wennen voor de doorgewinterde 'C' programmeur.
Hier volgen enkele voorbeelden:
cout << "Hello world\n"; // Output Hello world met een newline
cout << "Hello world" << endl; // Idem
int VarInt = 4;
int Var1,Var2;
float VarFloat = 3.14;
char *Str = "Hello";
cout << Str << VarInt << VarFloat << endl;
// Resulteert in Hello43.14
cout << setw(6) << setfil('*') << 134;
// Resulteert in ***134
cin >> VarInt;
// Leest 1 integer uit de input stream
cin >> Var1 >> Var2;
// Leest 2 integers uit de input stream
In 'C' schrijven we vaak voor standaard I/O:
while (var1 = getchar())
putchar(var1);
Dit schrijven we in 'C++' als:
while(cin >> var1)
cout << var1;
Terug naar inhoud opgave
In 'C++' kunnen we nu in plaats van de zeer omslachtige en overloaded functies
alloc() en free() waarbij we zelf de lengte van objecten moesten berekenen,
nu ook new en delete gebruiken. Dit hebben ze duidelijk van
de taal Pascal geleend, en werkt heel prettig en efficiënt.
void TestFunc()
{
int *IntPointer;
IntPointer = new int;
*IntPointer = 12;
cout << *IntPointer;
delete IntPointer;
}
void TestFunc()
{
int *IntPointer;
IntPointer = new int(100);
IntPointer(10) = 12;
cout << IntPointer(10);
delete [] IntPointer; // Let op bij arrays altijd [] gebruiken
}
Dit is zeer gemakkelijk in vergelijking met de oude 'C' methode.
Terug naar inhoud opgave
In 'C++' kunnen we nu met call by reference werken in plaats van pointers.
Dit maakt de code in bepaalde gevallen, heel wat duidelijker.
In 'C' zouden we het volgende schrijven:
void Swap(int *Var1, int *Var2)
{
int Tmp = *Var1;
*Var1 = *Var2;
*var2 = Tmp;
}
void TestFunc()
{
int V1, V2;
Swap(& V1, & V2); // Voorbeeld aanroep functie swap;
}
In 'C++' kunnen we dit op de volgende wijze doen:
void Swap(int& Var1, int& Var2)
{
int Tmp = Var1;
Var1 = Var2;
var2 = Tmp;
}
void TestFunc()
{
int V1, V2;
Swap(V1,V2); // Voorbeeld aanroep functie Swap in C++
}
Terug naar inhoud opgave
Bij de meeste compilers is het omschakelen van 'C' naar 'C++' simpelweg
het veranderen van de extensie van de source file van TEST.C in TEST.CPP
waardoor de compiler weet dat de source file een 'C++' file is. Als U dit
doet moet U dit voor alle files doen, omdat 'C' code geen 'C++' kan aanroepen.
Omgekeerd is wel via een speciale declaratie mogelijk maar ik raad het af
'C' en 'C++' files door elkaar te gebruiken. Verder kan het aanroepen van
zelfgeschreven library functies problemen gaan geven, omdat deze verwachten
volgens de 'C' conventie aangeroepen te worden.
Omdat 'C' een subset is van 'C++' kan elk 'C' programma ook door een 'C++'
compiler gecompileerd worden. Laat U niet afschrikken door het grote aantal
warnings, en zet vooral het warning level niet lager om het aantal warnings
terug te brengen. Besteed daarentegen eens een tijdje aan het plaatsen van
casts en de kans is groot dat U terloops ook nog een programmeer fout ontdekt.
Tot mijn verbazing zijn er nog steeds bedrijven waar code uitgeleverd word,
met een flink aantal compiler warnings, omdat de programmeur denkt dat hij
weet wat hij doet, en hij vindt dat de compiler te kieskeurig is. In mijn
visie is elke warning een mogelijke programmeer fout, en moet weggewerkt
worden.
Als U vragen of opmerkingen heeft, hoor ik het graag.
Terug naar inhoud opgave
C en C++ - De programmeertaal C++ Nog geen vragen binnen deze rubriek!
(c) Hein Pragt 1998
Ondanks de elektronische manuals, en de zeer uitgebreide help files bij
de huidige compilers, geef ik toch de voorkeur aan een boek. Een boek kun
je overal lezen, zelfs in bed, achtertuin of trein. Met een elektronisch
boek gaat dit niet zo best. (geloof me ik heb het geprobeerd!) Ik ben zelf
de trotse bezitter van een paar meter boeken, en ik schaf me gemiddeld één
boek per maand aan. Dit zijn ook boeken die zijdelings met mijn vak te maken
hebben, zoals de gehele reeks Dilbert boeken. Het probleem hierbij is vaak
het vinden van een goed boek. Heel vaak krijg ik een tip van een collega,
of zie ik een recensie in een tijdschrift. Van de boeken die de taal 'C'
en 'C++' behandelen, laat ik hier mijn favoriete boeken zien.
|
|
(Engelstalig)
Het eerste boek is The 'C' programming language van Brian Kernighan
en Dennis Ritchie. Ritchie is de oorspronkelijk bedenker van de taal
'C'. Dit bekende witte boekje is het standaard naslagwerk van iedere
'C' programmeur geworden. Ikzelf bezit de eerste editie, de huidige
tweede editie bevat ook de ANSI 'C' standaard. Ik heb het boek recent
nog gebruikt voor een voorbeeld van een PrintNum() functie. Het boek
bevat een uitgebreide beschrijving van de taal 'C' en is voorzien
van vele voorbeelden. De benadering is wel een beetje vanuit de Unix
omgeving, maar dit is niet raar als U bedenkt dat Unix voor 99 procent
in 'C' geschreven is.
Het ISB nummer is: 0-13-110163-3 en het is uitgegeven door Prentice-Hall,
Inc.
|
|
|
(Engelstalig)
Dit boek heet The Design and Evolution of C++ en het is geschreven
door Bjarne Stroustrup, de bedenker van C++. In dit boek beschrijft
Bjarne Stroustrup hoe de taal C++ ontstaan is en wat de oorspronkelijke
bedoelingen zijn van taal elementen van'C++'. Hij heeft met opzet
de ++ operatie van 'C' gekozen om aan te geven dat 'C++' een (verhoging
= verbetering) van 'C' is.
Het boek is niet bedoeld om de taal 'C++' te leren maar om de achtergronden
van het ontstaan van de taal te leren kennen. Ook staat in dit boek
de filosofie van Bjarne Stroustrup over hoe een programmeer taal zou
moeten werken, en welke concessies men moet doen om de taal succesvol
te gebruiken.
Het ISB nummer is: 0-201-54330-3 en het is uitgegeven door Addison-Wesley.
|
|
|
(Engelstalig)
Dit boek heet The C++ programming language en het is ook geschreven
door Bjarne Stroustrup. Dit boek is een zeer uitgebreide bijna 900
pagina's dik naslagwerk in een klein letter type, waarin de complete
taal beschreven staat. In mijn visie is dit boek de 'C++' versie van
het Kernighan & Ritchie boekje. Het boek is niet populair geschreven
en als U het helemaal wilt lezen, moet U er wel te tijd voor nemen.
Ook staan in dit boek veel voorbeelden, maar de tekst is vanuit een
redelijke kennis van programmeren geschreven, daarom dient U vrij
goed na te denken, tijdens het lezen van dit boek, en is het lezen
vrij vermoeiend. Het boek is echter een meesterwerk, en verdient dezelfde
status als witte boekje van K&R. Het enige nadeel van het boek
is dat het niet goedkoop is.
Het ISB nummer is: 0-201-88954-4 en het is uitgegeven door Addison-Wesley.
|
|
|
(Nederlandstalig)
Dit boek heet Leerboek Objectgeoriënteerd programmeren in
C++ en is geschreven door D.J. Duffy en J.C. Meeling,
die beiden werkzaam bij Datasim Education BV. Het is een zeer goed
boek over object georiënteerd programmeren, met als doeltaal
de taal C++. Het boek zelf is zeer goed van structuur met duidelijke
voorbeelden en opgaves per hoofdstuk. Ook staan er in het boek zeer
goede figuren om begrippen visueel duidelijk te maken. Het boek legt
de nadruk op goed en duidelijk programmeren in de taal C++ en behandeld
ook zaken als herbruikbaarheid en portabiliteit. Ook templates en
de STL worden in dit boek behandeld. Het boek leest heel prettig,
en de source code die in het boek gedrukt is kan via internet gedownload
worden. Het boek vereist wel enige basiskennis van de taal C of C++
en de concepten van object georiënteerd programmeren. De prijs
van het boek valt ook erg mee.
Het ISB nummer is: 90-395-0535-7 en het is uitgegeven door Academic
Service.
|
|
|
(Engelstalig)
Dit boek heet WRITING SOLID CODE, Microsoft's Techniques for
Developing Bug-Free 'C' programs. Dit boek is door een voormalig Microsoft
medewerker geschreven. Steve Maguire was hoofd ontwikkeling van een
van de software afdelingen van Microsoft. Hoewel ik zeker weet dat
Microsoft nooit bugvrije code geleverd heeft, geeft dit boek wel heel
veel nuttige tips om Uw programmeer stijl te verbeteren. Het boek
is heel luchtig en met veel praktijkvoorbeelden geschreven, en leest
heel prettig. Hoewel ik van collega's de kritiek hoor dat het boek
een constante reclame voor het ASSERT statement is, staan er ook heel
veel nuttige tips in het boek. Bij het beschrijven van een veel voorkomende
programmeer fout zult U vaak Uw eigen fouten herkennen. Het lezen
van dit boek geeft weer enkele nuttige stukken gereedschap in Uw (programmeer)
gereedschapskist.
Het ISB nummer is: 1-55615-551-4 en het is uitgegeven door Microsoft
Press.
|
|
|
(Nederlandstalig)
Dit boek heet C++ voor gevorderden, maar is mijn ogen een goed
standaard naslagwerk voor de taal 'C++'. De schrijver Leen Ammeraal
heeft meerdere goede boeken over de taal 'C' en 'C++' op zijn naam
staan. Het boek is vrij duidelijk leesbaar, en goed voorzien van voorbeelden.
Het meest verrassend is de prijs van c.a. 30 Gulden, dit is erg goedkoop
voor dit soort boeken. Het boek is ook vrij goed verkrijgbaar, en
als U 'C' programmeur bent, en een eerste stap richting 'C++' wilt
maken, is dit een uitstekend boek. Een groot voordeel is ook dat het
boek Nederlandstalig is.
Er is nu ook een tweede druk die in plaats van de hoofstuk
8,9 en 10 over het programmeren onder windows, nu een hele goede beschrijving
in drie hoofdstukken van de STL (Standard Template Library) geeft.
Het ISB nummer is: 90-395-0238-X en het is uitgegeven door Academic
Service.
|
Als U vragen of opmerkingen heeft, of een leuk boek kent, hoor ik het graag.
Berichtje aan Hein Pragt
(c) Hein Pragt 1998
Een tijdje geleden had ik een gesprek met een collega, en een bevriende
programmeur uit Amerika over een OOP aanpak ik 'C'. Ik moest namelijk een
bestaand project van het begin af aan herschrijven in 'C'. Voor deze embedded
applicatie was alleen een ANSI 'C' compiler beschikbaar. Als je aan OOP
gewend geraakt bent, mis je dit als je in standaard 'C' moet gaan werken.
Ik wist dat de eerst 'C' met classes puur standaard 'C' was, met een speciale
pre-processor. Dit gaf me het idee een systeem op te zetten in standaard
'C' om data hiding, en class interfaces te realiseren.
Na wat ruggespraak met collega's kwam hier een aardig systeem uit welke
ik nu gebruik als ik in standaard 'C' moet werken. De code die dit systeem
genereert is bijna niet groter dan een standaard 'C' aanpak.
Hoe werkt het!
Het voorbeeld bevat twee classes test1 en test2. Deze bestaan uit een include
file met de class definitie, en een 'C' file met de implementatie. De include
file bevat een structure, die pointers bevat naar de member functies van
de class, en een extern definitie van de class structure. Dit is op deze
wijze gedaan omdat in oudere 'C' compilers geen functies opgenomen kunnen
worden binnen structures, maar wel pointers naar functies.
Ik kreeg dit idee na het lezen van het boek van Stroustrup, the 'C++' programming
language, waarin hij er voorkeur aan geeft een class met alleen maar public
members een struct te maken.
/* -------------------------------------------------------------- */
/* Include file for test class */
/* (c) Hein Pragt 1998 */
/* -------------------------------------------------------------- */
struct _test1_class /* Class definition */
{
void (*func1)(int); /* Modifier */
int (*func2)(void); /* Selector */
};
extern const struct _test1_class test1;
De bijbehorende 'C' file bevat de implementatie van de class. Hier declaren
we ook de data die bij deze class hoort, de public data kan gewoon gedeclareerd
worden en dus ook door andere modules rechtstreeks benaderd worden. De private
variabelen declareren we static zodat ze alleen binnen deze module
benaderd kunnen worden. Data hiding is dus bereikt doordat de static
data binnen de class alleen door de member functie benaderd kunnen worden.
In dit voorbeeld heb ik een modifier en een selector functie gemaakt. De
member functies zijn ook static zodat ze nooit rechtstreeks aangeroepen
kunnen worden, maar alleen via de interface structure.
Een modifier member functie veranderd iets aan de staat van de interne variabelen,
een selector member functie geeft een interne waarde terug aan de module
van waar deze aangeroepen werd. De struct is de gedefinieerde interface.
Het vullen van de functie pointers gebeurd tijdens het compileren zodat
een aparte constructor/destructor niet direct nodig zijn. Deze kunnen echter
gewoon als member functies toegevoegd worden. Ze moet echter wel apart aangeroepen
worden, omdat dit niet automatisch gebeurd.
/* ---------------------------------------------------------------- */
/* Implementation file of test1 class. */
/* (c) Hein Pragt 1998 */
/* */
/* Demonstration of data and member function hiding in standard 'C' */
/* ---------------------------------------------------------------- */
#include "test1.h" /* Definition of test1 class */
/* ------------------------------------ */
/* These member functions are static */
/* and can only be called trough the */
/* class member interface. */
/* ------------------------------------ */
static void func1a(int);
static int func2a(void);
/* ------------------------------------ */
/* Local data cannot be accesed outside */
/* this module and be accessed trough */
/* class members functions. */
/* ------------------------------------ */
static int local_data;
/* Trick to init the class */
struct const _test1_class test1 = { func1a, func2a };
/* ------------------------------------ */
/* Class function 1 */
/* This is a modifier. */
/* ------------------------------------ */
static void func1a(int b)
{
printf("Test1 class func1 set local variable to %d and adds 100\n",b);
local_data = b + 100;
}
/* ------------------------------------ */
/* Class function 2 */
/* This is a selector. */
/* ------------------------------------ */
static int func2a()
{
printf("Test1 class func2 return the value %d\n",local_data);
return(local_data);
}
Overerving (dit is ook niet mijn favoriete deel van OOP) is met dit
systeem echter niet mogelijk. Maar het kunnen opzetten van een programma
met ingekapselde objecten, en goed gedefinieerde interfaces is al een stap
in de goede richting. Het systeem staat en valt wel met consequent gebruik.
Het is geen beveiliging tegen slecht programmeren.
Als laatste volg de main code die de class gebruikt.
/* ---------------------------------------------------------------- */
/* Main module uses test class. */
/* (c) Hein Pragt 1998 */
/* */
/* Demonstration of data and member function hiding in standard 'C' */
/* ---------------------------------------------------------------- */
#include "test1.h" /* Get definition of test1 class */
#include "test2.h" /* Get definition of test2 class */
main()
{
int res;
printf("\n\nDit is een test van OOP methode in standard 'C'\n\n");
test1.func1(234); /* Call a modifier function */
res = test1.func2(); /* Call a selector function */
printf("The return value is: %d \n\n",res);
test2.func1(333); /* Call a modifier function */
res = test2.func2(); /* Call a selector function */
printf("The return value is: %d \n\n",res);
}
Om het wat eenvoudiger te maken heb ik hier de volledige sourcecode van
dit voorbeeld gezet, zodat U dit kunt downloaden. Ik sta open voor suggesties,
verbetering (taalfouten) en andere reacties. Wilt U reageren (Wat uiteindelijk
mijn bedoeling is), stuur me dan een email. Berichtje
aan Hein Pragt Ik lees de email zeker eens per dag.
De sourcecode kunt U hier downloaden.
(c) Hein Pragt 1999
Na jaren met Microsoft Visual C++ gewerkt te hebben, heb ik op aanraden
van een collega, een tijdje met C++ Builder van Borland (Inprise) gewerkt.
Ik was erg onder de indruk van C++ Builder maar na een paar maanden keek
is wat ontnuchterd naar beide compilers en moest voor mezelf een besluit
maken welke compiler is verder zou gaan gebruiken, voor nieuwe projecten.
Dit leverde een weloverwogen keuze op, in het voordeel van Microsoft Visual
C++. Dit ondanks mijn jarenlange kritiek op Microsoft. Ik moet bekennen
dat Visual C++ een erg goed product is. Hieronder staat een persoonlijk
objectief vergelijk tussen Visual C++ en C++ Builder. De versies zijn 4.2
en 5.0 voor Visual C++ en versie 3 voor C++ Builder. Het blijft echter mijn
mening, als U het er niet mee eens bent laat het mij dan weten via een email.
| Features |
|
Visual C++ |
|
C++ Builder |
| Class Library. |
++ |
MFC is vrij universeel en compiler onafhankelijk. |
-- |
VCL is alleen met Delphi of C++ Builder te gebruiken. |
| Overerving van standaard classes. |
++ |
Omdat MCF in C++ geschreven en de class hiërarchie goed in
elkaar zit, kunnen goed classes afgeleid worden van de MCF classes.
|
-- |
VCL is in Delphi (pascal) geschreven en dat is niet direct zo eenvoudig
voor het afleiden van C++ classes. |
| Nieuwe technologie |
++ |
Microsoft update de compilers vrij regelmatig en deze hebben altijd
de beste support voor de Windows API. Dit is niet zo verwonderlijk
omdat deze ook door Microsoft gemaakt wordt. |
-- |
C++ Builder loopt wat achter op Visual C++ op dit gebied. |
| Debuggen van MCF en VCL. |
++ |
Omdat MCF als debug DLL beschikbaar is kan direct van Debug naar
Release versie omgeschakeld worden via een workspace setting. |
-- |
VCL kan niet zo eenvoudig tussen Debug en Release heen een weer
schakelen. |
| Onderhoud van classes. |
-- |
In Visual C++ kan via de class wizzard vrij eenvoudig code voor
nieuwe objecten toegevoegd worden, echte het verwijderen of wijzigen
moet met de hand gebeuren. Dit is wat lastig hoewel dit in versie
5 weer wat verbeterd is. |
++ |
De Object Inspector is een hele eenvoudige en gemakkelijke tool
om Objecten te maken en te onderhouden. Voor beginners in C++ is dit
veel eenvoudiger. |
| Abstractie niveau. |
-- |
De MCF classes zijn een dunne laag over de Windows API, deze is
nog redelijk complex en vereist een redelijke kennis van de Windows
API. Dit levert wel wat compactere code op. |
++ |
VCL staat op een behoorlijk hoog niveau boven de Window API. Dit
vergt minder kennis van de Windows API, en is wat eenvoudiger te leren.
|
| Help bestanden. |
++ |
De help bestanden zij heel uitgebreid en heel goed van structuur.
|
-- |
Ondanks vriendelijke interface, weinig documentatie van matige
kwaliteit. |
| Meegeleverde voorbeelden. |
++ |
Veel complete voorbeeld applicaties worden op de CD meegeleverd.
|
-- |
Slechts enkele voorbeeld programma's worden meegeleverd. |
| Support |
++ |
Veel gebruikers, en uistekende support via Internet, met regelmatig
updates en bugfixes. |
-- |
Niet zoveel gebruikers, en niet zovaak updates via de internet
site. |
| Ontwikkel omgeving. |
-- |
Visual C++ en MFC zijn vrij dwingend in het opzetten van een programma
structuur. Het kost meer tijd om het systeem te begrijpen. Visual
C++ is niet echt een visuele ontwikkel omgeving. |
++ |
Zeer eenvoudig te gebruiken, en heel vrij in opzet, en de ontwikkel
omgeving is zeer visueel opgezet. |
| Database support. |
-- |
Bij Visual C++ word standaard geen DBMS meegeleverd. Dit is een
sterk minpunt voor Microsoft. |
++ |
De BDE database engine is bijzonder sterk, en word standaard meegeleverd.
Ook is de BDE eenvoudig in gebruik en in de standaard component library
opgenomen. |
| Snel applicaties maken. (RAD) |
-- |
Bij Visual C++ moet je wat meer nadenken voor je een applicatie
maakt, het is wat minder geschikt voor RAD. |
++ |
Het is heel eenvoudig snel een programma te ontwikkelen, en snel
een user interface te bouwen. C++ Builder is heel goed voor RAD en
prototyping. |
| Betrouwbare code. |
++ |
In de periode dat ik DirectX applicaties maakte was de code van
Visual C++ compacter, sneller en betrouwbaarder. |
++ |
De code was wat minder snel dan de Visual C++ code, en de code
was minder betrouwbaar. |
Slot conclusie.
Beide producten hebben hun voor en nadelen, en zijn bijna even goed. Voor
de beginnende C++ programmeur is waarschijnlijk C++ Builder een goede keuze.
Een groot voordeel voor C++ builder is ook de meegeleverde Database Engine,
dit is een groot nadeel van Visual C++. Ook is C++ Builder in het voordeel
als er snel even een applicatie gemaakt moet worden. Echter voor solide
zakelijke applicaties zal ik de voorkeur geven aan Visual C++, mede omdat
het betrouwbare, compacte en snelle code maakt.
(c) Hein Pragt 1999
Voordat ik begin uit te leggen wat object georiënteerd (vanaf nu OO)
programmeren is, begin ik met een definitie wat objecten zijn. Objecten
zijn alle dingen die wij kunnen bevatten, met duidelijk afgebakende grenzen.
Voorbeelden zijn, een punt op het scherm, een pomp, een bankrekening, een
computer, een mens of een programmeertaal. Twee verschillende objecten zijn
duidelijk van elkaar te onderscheiden.
Een object heeft een aantal kenmerken:
Een identiteit is de unieke code of naam waarmee we twee objecten
van elkaar onderscheiden, voorbeelden zijn een boek of een bankrekening.
De toestand is de huidige waarde van de interne structuur van
een object, een voorbeeld is een bankrekening met een saldo van 1023 gulden.
Het gedrag van een object zijn de diensten die het verleent aan
de buitenwereld. In het geval van een bankrekening kan dit het opvragen
van het saldo of het verhogen van het saldo zijn.
De buitenwereld heeft geen directe toegang tot het saldo van de bankrekening,
maar kan alleen via de boodschappen (member functies) de huidige toestand
opvragen, of iets aan de huidige toestand te veranderen.
Een class is een definitie van een object, waarmee instances (echte objecten)
van de class gemaakt kan worden. Een class op zich is geen object, er kunnen
objecten mee gemaakt worden. Van een class kunnen we meer dan een object
(instances) maken. De class is vergelijkbaar met een gietvorm waar we veel
dezelfde beeldjes mee kunnen gieten.
In de class definiëren we een interface. We kunnen alleen met een object
communiceren via deze interface. Ook definiëren we in de class de interne
data, waarin we de toestand van een object opslaan. Interne data is dus
ingekapseld en niet direct benaderbaar door de buitenwereld.
OO software is gebaseerd op deze objecten. Een object kunnen we beschouwen
als een "gesloten apparaat" met een vast gedefinieerde interface. We hoeven
niet te weten wat er zich in het object bevind, we kennen de interface waarmee
we communiceren met het object.
Een voorbeeld is een televisie toestel.
We hoeven niet weten wat er in de T.V. zit, we gebruiken alleen de knoppen
en het scherm als interface. Als we een andere zender willen kiezen, veranderen
en we niet de afstemkring door binnen in het toestel aan een van de onderdelen
te draaien, maar we geven de interface via een knop de opdracht op een andere
zender af te stemmen. Via deze knoppen kunnen we ook zenders zoeken en in
het geheugen van de T.V. opslaan. Hoe dit intern gebeurt willen we niet
weten, en is voor het normaal gebruik van het toestel niet belangrijk. Intern
kan dit in verschillende toestellen anders opgelost zijn, vanuit de interface
zien we hetzelfde. Deze inkapseling van data en methodes is de basis van
OO programmeren.
De interface functies zijn ook weer onder te verdelen in vier soorten:
Constructors. Dit is de member functie die gebruikt word om een
object een begin toestand te geven. Deze zal bij het creëren van
een object zorgen voor een voorinstelling van de waardes van interne variabelen.
Destructors. Deze member functie ruimt een object netjes op uit
het geheugen, als de levenduur van het object afgelopen is.
Modifiers. Dit zijn member functies die iets aan de interne toestand
van het object veranderen, bijvoorbeeld in het geval van de bankrekening
kan de methode StortBedrag het saldo veranderen.
Selectors. Dit zijn member functies die de interne toestand van
een object terugmelden. Deze zullen niets aan de interne toestand veranderen.
Dit is dus een read-only bewerking, het mag niets aan de interne toestand
van het object veranderen.
De constructor en destructor zijn interne functies van het object, de modifier
en de selector zijn van buiten het object te gebruiken.
Doordat de buitenwereld geen directe toegang heeft op de interne data van
een object, kan via de interface functies bijvoorbeeld validatie plaatsvinden.
Als gedefinieerd is dat een bankrekening niet negatief mag zijn kan de member
functie VerlaagSaldo een controle uitvoeren of het saldo door deze bewerking
niet negatief kan worden. In dit geval kan de member functie een fout afhandeling
starten of een foutmelding genereren.
De interface bewaakt dus de interne toestand van een object.
De tegenhanger van OO programmeren is het procedure gericht programmeren.
Hier staan de bewerkingen centraal, in tegenstelling van OO programmeren
waar de gegevens en hun toestand centraal staan. In OO begint men met een
data model, waarna men deze via objecten in categorieën onderbrengt,
om daarna de interface en de bewerkingen te definiëren. Dit is duidelijk
een andere aanpak, die het ook nodig maakt eerst over het programma en het
data model na te denken. Dit in contrast met procedure gericht programmeren
waar vaak een globale opzet van een programma word gemaakt, waarna deze
procedures uitgewerkt worden. Dit is niet per definitie een slechtere aanpak,
maar een andere, die ook zijn voordelen kan hebben.
Ik heb wel eens te horen gekregen, als is een ontwerp op papier aan het
maken was, "wanneer begin je nu met het project". Deze mensen
dachten dat het inkloppen van code het programmeren is. Dit is echter maar
een klein deel van het programmeer werk. Het meeste is ook zonder computer
te doen.
Een tweede eigenschap van OO programmeren is overerving.
Als we eenmaal een class gedefinieerd hebben, ligt deze vast. Als er nu
een specialisatie plaats moet vinden, kan de reeds ontworpen class als basis
dienen voor een nieuwe class. De nieuwe class bevat alle onderdelen van
de oorspronkelijke class, met een aantal toevoegingen speciaal voor de nieuwe
class. Als we een bankrekening zonder rente gedefinieerd hebben met een
groot aantal bewerkingen, kunnen we hiervan een rekening met rente afleiden.
De bewerkingen die we kunnen uitvoeren op de oorspronkelijke rekening kunnen
we ook uitvoeren op de rekening met rente. Deze rekening heeft echter een
paar uitbreidingen t.o.v. de oude rekening, en dat is een rentepercentage
variabele, een functie om het rentepercentage op te vragen en een functie
om het rentepercentage te veranderen. Ook zal er een functie moeten komen
om de rente bij te boeken. De code om het saldo op te vragen en het saldo
af te boeken hoeven we niet opnieuw te schrijven.
Dit is een eigenschap van OO programmeren die ik nogal eens uit de hand
zie lopen. Een goede class hiërarchie opbouwen is een kunst, en soms
zie je een ad-hoc class hiërarchie die ondoorzichtig en niet te onderhouden
is.
Het werken met OO is geen garantie voor goede en goed onderhoudbare
code. Een paar goede voorbeelden van een class hiërarchie zijn OWL
van Inprise en MFC van Microsoft.
OO werken ten opzichte van procedureel programmeren betekend vaak de je
veel vrijheden die je had moet opgeven en binnen een strakkere structuur
moet werken. Dit voorkomt echter heel veel basis programmeer fouten, zodat
het resultaat beter, en beter onderhoudbaar is.
Deze vorm van jezelf de beperkingen van een goede structuur opleggen, schrikt
sommige 'C' en assembler programmeurs nog wel eens af. Een collega van mij
plaagt me wel eens, als ik weer iets met de bestaande code wil doen waarin
niet voorzien is, dat beperkingen opleggen geheel in de stijl van OO programmeren
is. Ik probeer dan uit te leggen dat ik vanuit de bestaande code deze functionaliteit
niet kan toevoegen, maar dat dit in een OO omgeving eenvoudig te doen zou
zijn.
Het grote voordeel van OO programmeren is dat het uitnodigt tot goed gestructureerd
werken, en dat je in staat bent goede interfaces te maken. Data hiding is
in mijn visie een van de beste onderdelen van OO.
(c) Hein Pragt 1999
Elke nieuwe techniek is de moeite van het bestuderen waard.
Graag reageer ik op het artikel van prof. drs. Maarten Boasson
in pt Embedded Systems van Februari 1999. Hoewel ik het in sommige op zichten
wel eens ben met de heer Boasson, wil ik toch een aantal opmerkingen maken
over zijn artikel en de aangehaalde voorbeelden.
Er wordt een voorbeeld met autorijden gebruikt dat niet correct is. Het
autorijden is de laatste tien jaar sterk verbeterd doordat de autoindustrie
telkens weer met verbeteringen in het ontwerp kwam en nieuwe technologie
is gaan toepassen. Ook wordt in het voorbeeld popnagels gebruikt als verbindingstechniek,
om lijmen te vervangen. Hier zou men dus een gloednieuw en betere verbindingsmethode
zoals lijmen (zelfs vliegtuigenonderdelen worden tegenwoordig gelijmd
in plaats van popnagelverbindingen) door een verouderde techniek als popnagels
vervangen. Dit is dus een slecht voorbeeld. Het objectgeoriënteerde
ontwerpen is een nieuwe techniek die een aanvulling moet zijn op bestaande
technieken. Geen enkele techniek is dusdanig goed dat het alle voorgaande
technieken volledig kan vervangen. Dit mag echter geen reden zijn om elke
nieuwe techniek bij voorbaat af te wijzen als zijnde onbruikbaar.
Een goed vergelijk is de elektronica-industrie. De ontwerper heeft de
keuze uit een groot aantal standaardcomponenten en maakt daarmee een schakeling.
Een component heeft een door de fabrikant bepaald aantal poorten en functionaliteiten,
en de ontwerper moet daar in zijn ontwerp rekening mee houden. Dit betekent
dat er wel eens een paar ongebruikte poorten in zijn ontwerp zitten en
dat hij, als hij een poortje tekort komt, soms een tussenoplossing moet
vinden want we willen (of moeten) zo weinig mogelijk componenten gebruiken.
Het grote voordeel voor de ontwerper is dat de eigenschappen van de standaardcomponenten
goed zijn beschreven, de componenten hun stabiliteit reeds hebben bewezen,
en dat er second sources zijn. Dit leidt tot een beter en efficient ontwerpproces.
In de elektronica zullen weinig mensen hun eigen componenten samenstellen,
tenzij het om grote aantallen gaat.
In de software-industrie wordt echter nog heel vaak voor elk nieuw probleem
een nieuwe oplossing bedacht. In de ideale situatie zou het ontwerpen
van software vergelijkbaar moeten zijn aan het ontwerpen van hardware.
Het gebruik van standaardcomponenten (lees: objecten zou tot betere
en sneller te ontwikkelen producten kunnen leiden. Dit is niet iets wat
binnen een korte tijd kan worden gerealiseerd, maar door nieuwe ontwikkelingen
in standaard herbruikbare componenten op te zetten zal deze (objectgeoriënteerde)
ontwerpmethode langzaam zijn intrede doen. Oude en nieuwe technieken kunnen
langzaam in elkaar overgaan.
Het grote probleem is dat veel mensen in bestaande organisaties al jaren
met een bepaalde techniek hebben gewerkt en het gevoel hebben dat ze de
nieuwe ontwikkelingen niet meer kunnen bijhouden. Als resultaat hiervan
wordt de nieuwe technologie vaak afgedaan als "nieuwe fratsen en
geneuzel met classes" en dergelijke. Dit is vaak gebaseerd op de
angst het niet allemaal meer te kunnen bijbenen, of na jaren nog een andere
wijze van denken te moeten leren. Echter de ontwikkelingen in de techniek
staan niet stil, en men zal steeds om nieuwe gereedschappen in de (software)
gereedschapskist vragen. Dit is een natuurlijk proces dat niet te stuiten
is. Mijn mening is dan ook dat elke nieuwe techniek de moeite van het
bestuderen waard is, en ook al is zij niet direct toepasbaar, op een dag
kan ze de oplossing van een bepaald probleem zijn.
HEIN PRAGT Juni 1999
Last update: 12-06-2003
Disclaimer.
Hoewel de heer Hein Pragt de informatie beschikbaar op deze pagina met grote zorg
samenstelt, sluit de heer Pragt alle aansprakelijkheid uit met betrekking tot
de informatie die, in welke vorm dan ook, via zijn site wordt aangeboden. Het
opnemen van een afbeelding of verwijzing is uitsluitend bedoeld als een mogelijke
bron van informatie voor de bezoeker en mag op generlei wijze als instemming,
goedkeuring of afkeuring worden uitgelegd, noch kunnen daaraan rechten worden
ontleend. Op de artikelen van de heer Pragt op deze Internet Site rust
auteursrecht. Overname van informatie (tekst en afbeeldingen) is uitsluitend
toegestaan na voorafgaande schriftelijke toestemming van de rechthebbende. Voor vragen
over copyright en het gebruik van de informatie op deze site kunt u contact opnemen
met: (email: copyright@heinpragt.com)
Webdesign: © Hein Pragt
Fotografie: © Hein Pragt
Auteur: © Hein Pragt (Veenendaal - Utrecht - Nederland)
Privacy beleid
Wij maken gebruik van externe advertentiebedrijven om advertenties weer te geven wanneer u onze website
bezoekt. Deze bedrijven gebruiken mogelijk informatie (niet uw naam, adres, e-mailadres of telefoonnummer)
over uw bezoek aan deze of aan andere websites om advertenties weer te geven over goederen en services
waarin u wellicht geïnteresseerd bent. Als u hierover meer informatie wenst of als u wilt voorkomen dat
deze bedrijven deze informatie gebruiken, klikt u op
deze link.
|
|