I N H O U D S T A B E L. 1. Uitbreidingen en verbeteringen in C++ t.o.v. C... 8



Vergelijkbare documenten
Een typisch programma in C en C++ bestaat uit een aantal onderdelen:

9 Meer over datatypen

Hoofdstuk 1: Inleiding. Hoofdstuk 2: Klassen en objecten Datahiding: afschermen van implementatiedetails. Naar de buitenwereld toe enkel interfaces.

Introductie in C++ Jan van Rijn. September 2013

Datatypes Een datatype is de sort van van een waarde van een variabele, veel gebruikte datatypes zijn: String, int, Bool, char en double.

Datastructuren Werkcollege Intro

Vakgroep CW KAHO Sint-Lieven

Gertjan Laan Aan de slag met C++ Vijfde editie

C++ C++ als een verbetering van C. Abstracte datatypen met classes. Constructoren en destructoren. Subklassen. binding van functies

Java. Basissyllabus. Egon Pas

HOGESCHOOL VAN AMSTERDAM Informatica Opleiding. CPP 1 van 10

Programmeermethoden. Functies vervolg. Walter Kosters. week 5: 1 5 oktober kosterswa/pm/

Datastructuren: stapels, rijen en binaire bomen

Een korte samenvatting van enkele FORTRAN opdrachten

Examen Software Ontwikkeling I 2e Bachelor Informatica Academiejaar Januari, **BELANGRIJK** : Schrijf je naam onderaan dit blad

Programmeermethoden. Recursie. week 11: november kosterswa/pm/

Datastructuren: stapels, rijen en binaire bomen

4EE11 Project Programmeren voor W. College 2, , Blok D Tom Verhoeff, Software Engineering & Technology, TU/e

Deel 1: Arduino kennismaking. Wat is een microcontroller, structuur van een programma, syntax,

Objectgeoriënteerd programmeren in Java 1

Inleiding Een terugblik op C... 3

Instructies en blokken

Objectgeoriënteerd Programmeren in C++

Voorwoord bij de zesde druk 3

Programmeermethoden. Recursie. Walter Kosters. week 11: november kosterswa/pm/

Kleine cursus PHP5. Auteur: Raymond Moesker

Zelftest Programmeren in Java

Uitwerking Aanvullend tentamen Imperatief programmeren Woensdag 24 december 2014, uur

Programmeren in C# Samenvatting van C#

Variabelen en statements in ActionScript

Syntax- (compile), runtime- en logische fouten Binaire operatoren

Constanten. Variabelen. Expressies. Variabelen. Constanten. Voorbeeld : varid.py. een symbolische naam voor een object.

Datastructuren Programmeeropdracht 3: Expressies. 1 Expressies. Deadline. Dinsdag 8 december 23:59.

Visual Basic.NET. Visual Basic.NET. M. den Besten 0.3 VB. NET

Programmeermethoden. Pointers. Walter Kosters. week 10: november kosterswa/pm/

Programmeren in Java les 3

Inleiding C++ Coding Conventions

Een eenvoudig algoritme om permutaties te genereren

Turbo Pascal (deel 1)

Universiteit van Amsterdam FNWI. Voorbeeld van tussentoets Inleiding programmeren

Week 2 : Hoofdstukken 2 en 6; extra stof: inleiding pointers

Uitwerking Tweede deeltentamen Imperatief programmeren - versie 1 Vrijdag 21 oktober 2016, uur

Objectgeoriënteerd Programmeren in C++

Tentamen Programmeren in C (EE1400)

1.1 Programmeren en voorbereiding

Voorbeeldtentamen Inleiding programmeren (IN1608WI), Oktober 2003, , Technische Universiteit Delft, Faculteit EWI, Afdeling 2.

Lineaire data structuren. Doorlopen van een lijst

Modelleren en Programmeren

C++ voor C-kenners. Jeroen Fokker Informatica Instituut Universiteit Utrecht januari 1995

Programmeermethoden NA. Week 5: Functies (vervolg)

UNIVERSITEIT ANTWERPEN FACULTEIT WETENSCHAPPEN DEPARTEMENT WISKUNDE-INFORMATICA OBERON CODE CONVENTIONS

Programmeren in C++ (deel 1)

continue in een for, while of do lus herhaalt de lus vroegtijdig. De volgende herhaling wordt onmiddellijk begonnen.

Modelleren en Programmeren

Arrays. Complexe datastructuren. Waarom arrays. Geen stijlvol programma:

Als een PSD selecties bevat, deelt de lijn van het programma zich op met de verschillende antwoorden op het vraagstuk.

Online c++ leren programmeren:

Programmeren in C++ Efficiënte zoekfunctie in een boek

Programmeermethoden NA. Week 5: Functies (vervolg)

6,1. Samenvatting door een scholier 1809 woorden 28 oktober keer beoordeeld. Informatica

EE1400: Programmeren in C BSc. EE, 1e jaar, , 2e college

VAN HET PROGRAMMEREN. Inleiding

Tentamen Programmeren in C (EE1400)

Programmeren in Java 3

Examen Programmeren 2e Bachelor Elektrotechniek en Computerwetenschappen Faculteit Ingenieurswetenschappen Academiejaar juni, 2010

int getaantalpassagiers{): void setaantalpassagiers(int aantalpassagiers);

EE1400: Programmeren in C BSc. EE, 1e jaar, , 3e college

10 Meer over functies

Om de libraries te kunnen gebruiken, moet de programmeur (een deel van) zijn programma in C/C++ schrijven.

HOOFDSTUK 3. Imperatief programmeren. 3.1 Stapsgewijs programmeren. 3.2 If Then Else. Module 4 Programmeren

Dynamisch geheugen beheer

Inhoud leereenheid 4. Inleiding JavaScript. Introductie 99. Leerkern 100. Zelftoets 108. Terugkoppeling 109

Inhoud leereenheid 7c. JavaScript: Objecten en functies. Introductie 59. Leerkern 60. Samenvatting 82. Opdrachten 83. Zelftoets 89.

Modeleren. Modelleren. Together UML. Waarvan maken we een model? overzicht les 14 t/m 18. ControlCenter 6.2

Tentamen Imperatief en Object-georiënteerd programmeren in Java voor CKI

Algoritmen en Datastructuren 1. Functies

Klassen & objecten, overerving, abstracte klassen, debuggen, interfaces, formulieren, polymorfie, statische methoden, event-handlers

4 Invoer en uitvoer. 4.1 Toegang tot de standaardbibliotheek

Arduino Zuid-Limburg Workshop 2

Zelftest Inleiding Programmeren

Python. Vraag 1: Expressies en types. Vraag 1 b: Types -Ingebouwde functies- Vraag 1 a 3/10/14

De standaard programmeertaal

Hoofdstuk 20. Talstelsels

Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 6 november 2015, uur

Programmeermethoden. Arrays (vervolg 2) Walter Kosters. week 9: 6 10 november kosterswa/pm/

Veel succes! 1. Deze opgave bestaat uit een aantal deelvragen. Houd het antwoord kort: één of twee zinnen per onderdeel kan al genoeg zijn.

DOMjudge teamhandleiding

Software-Ontwikkeling I Academiejaar

PROS1E1 Gestructureerd programmeren in C Dd/Kf/Bd

Zelftest Programmeren in PL/I

Programmeermethoden. Controle-structuren. Walter Kosters. week 3: september kosterswa/pm/

Programmeren (1) Examen NAAM:

Syntax van opdracht. opdracht. expressie. variabele. = expressie ; klasse naam. methode naam. property naam += object

Examen Programmeren 2e Bachelor Elektrotechniek en Computerwetenschappen Faculteit Ingenieurswetenschappen Academiejaar juni, 2010

Wat zijn de verschillen tussen SPSS 9 en SPSS 10?

VI. Klassen en objecten

Teamhandleiding DOMjudge (versie 2.2.0muKP) 31 mei 2008

Deeltentamen Grammatica s en ontleden 22 december 2005

Derde deeltentamen Imperatief programmeren - versie 1 Vrijdag 7 november 2014, uur

Objectgericht programmeren 1.

Transcriptie:

1 I N H O U D S T A B E L 1. Uitbreidingen en verbeteringen in C++ t.o.v. C... 8 1.1 Inleiding...8 1.2 Het gebruik van de iostream bibliotheek...8 1.2.1 In- en uitvoer...8 1.2.2 De iostream bibliotheek...8 1.2.2.1 Algemeen...8 1.2.2.2 Het begrip stream...9 1.2.2.3 De verschillende streamklassen...9 1.2.3 Uitvoer...9 1.2.4 Invoer... 10 1.2.5 I/O manipulatoren... 10 1.2.5.1 Opmaak van getallen... 10 1.2.5.2 Algemene opmaak... 11 1.2.5.3 Uitlijnen... 11 1.3 Het plaatsen van de declaraties van variabelen... 12 1.4 Typeconversie... 13 1.4.1 Converteren... 13 1.4.2 Typedef... 13 1.5 Het type const... 14 1.5.1 Het const type... 14 1.5.2 Expressies... 14 1.6 Het type referentie... 15 1.6.1 Probleem... 15 1.6.2 Het type referentie... 17 1.6.2.1 Het referentie datatype... 17 1.6.2.2 Programmavoorbeeld... 17 1.6.3 Initialisatie van een referentie... 17 1.6.4 Referentie als functieparameter... 18 1.6.5 Verschil tussen pointer en referentie... 19 1.6.6 Referenties als terugkeerwaarde... 22 1.7 Initialisatie van variabelen... 23 1.8 Overloaded functies... 24 1.8.1 Overloading... 24 1.8.2 Gebruik... 25 1.8.3 Functie aanroepen met argumenten van verschillend type... 25 1.8.3.1 Voorbeeld met automatische convertie... 25 1.8.3.2 Voorbeeld met verlies van data... 26 1.9 Type-safe linken... 26 1.9.1 Probleem... 26 1.9.2 Type-safe linken... 26 1.10 Inline functies... 27 1.10.1 Inline specifier en inline functie... 27 1.10.2 Functie versus macro... 27 1.10.3 Vraag aan de compiler... 29 1.11 Default functie-argumenten... 29 1.11.1 Default functie-argumenten... 29 1.11.2 Voorbeeld... 30

2 1.11.3 Default argumenten en functie-overloading... 30 1.11.4 Wat kan met functie-overloading en default argumenten?... 32 1.12 New en delete... 32 1.12.1 Dynamische geheugenallocatie... 32 1.12.2 De-allocatie van geheugen... 33 1.12.3 Dynamische array... 33 1.12.4 Overloaden van de new operator... 34 1.12.5 Gebruik van de set_new_handler... 35 1.13 Namespaces... 36 1.13.1 Het concept namespaces van C++... 36 1.13.2 Gebruik van variabelen... 36 1.14 Commentaar... 37 1.15 Oefeningen... 37 2. Klassen en objecten... 38 2.1 Creatie van een nieuw datatype in C++... 38 2.1.1 Het datatype klasse... 38 2.1.2 Programma-voorbeeld 1 en bespreking... 39 2.1.3 Programma-voorbeeld 2 en bespreking... 41 2.2 Definitie van een klasse en OOP... 43 2.2.1 Definitie van een klasse... 43 2.2.2 OOP... 44 2.2.2.1 OOP versus procedureel programmeren... 44 2.2.2.2 De principes van OOP... 44 2.3 Opbouw van een klasse... 45 2.4 Toegangscontrole tot klasseleden... 46 2.5 Constructoren en destructor... 48 2.5.1 Constructor... 48 2.5.2 Default constructor... 50 2.5.3 Constructor met argumenten... 51 2.5.4 Constructor overloading... 52 2.5.5 Constructor met default argumenten... 53 2.5.6 Constructor overloading en default argumenten... 54 2.5.6.1 Probleem en oplossing... 54 2.5.6.2 Programma voorbeeld... 54 2.5.7 Destructor... 55 2.6 Object als argument van een lidfunctie... 57 2.7 Constante objecten en constante lidfuncties... 59 2.7.1 Constante objecten... 59 2.7.2 Constante lidfuncties... 59 2.8 Objecten als functiewaarde... 60 2.9 Object als referentie argument... 62 2.10 Oefeningen... 64 3. Conversie, klassen en operatoren... 64 3.1 Algemeen... 64 3.2 De copy constructor... 65 3.2.1 Algemeen... 65 3.2.2 Programmavoorbeeld... 66 3.2.3 Default copy constructor... 67 3.3 Constructoren en conversie... 68 3.3.1 De conversie constructor... 68 3.3.2 Conversie door een constructor met default argumenten... 69 T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

3 3.3.3 Voorwaardelijke compilatie... 71 3.3.4 Conversie na de initialisatie... 71 3.3.5 Conversie met andere constructoren... 74 3.4 Overzicht en samenvatting constructoren... 74 3.5 Operator overloading... 75 3.5.1 Algemeen... 75 3.5.2 Lidfunctie die de som berekent van twee objecten... 75 3.5.3 Tijdelijk object door een constructor laten maken... 77 3.5.4 De operator + in plaats van de somfunctie... 78 3.5.5 Operatoren voor overloading... 79 3.5.6 De this-pointer... 80 3.5.6.1 De this-pointer... 80 3.5.6.2 Overladen van een assignment-operator... 81 3.6 Friend operatoren... 82 3.6.1 Friend... 82 3.6.2 Probleem... 82 3.6.3 De friend operator... 83 3.7 Conversie van een klasse naar een standaardtype... 85 3.7.1 De conversie-functie... 85 3.7.2 Impliciete en expliciete aanroep van een conversie-functie... 86 3.8 Conversie tussen klassen... 87 3.9 Oefeningen... 89 4. Overerving... 90 4.1 Overerving (E: inheritance)... 90 4.1.1 Basisklasse en afgeleide klasse... 90 4.1.2 Doelstellingen van overerving... 90 4.2 De basisklasse... 91 4.3 Afgeleide klasse... 92 4.3.1 Constructie van een afgeleide klasse... 92 4.3.2 Geheugenlayout van een afgeleid object... 92 4.3.3 Programmavoorbeeld... 93 4.3.4 Private, public en protected... 94 4.3.5 Default-constructor van de basisklasse... 94 4.3.6 Eigen constructor van een afgeleide klasse... 95 4.3.7 Initializer... 95 4.4 Functie-overriding... 96 4.4.1 Functie-overriding... 96 4.4.2 Programma met overriding van de print-functie... 97 4.4.3 Functie overriding versus functie overloading... 99 4.4.4 Overridden functie aanroepen vanuit de afgeleide klasse... 100 4.5 Toegangsregels... 100 4.5.1 Algemeen... 100 4.5.2 Toegangsregels van een privaat afgeleide klasse... 101 4.5.3 Toegangsregels voor een publiek afgeleide klasse... 101 4.5.4 Voorbeeld... 102 4.5.5 Overzichtstabel... 103 4.5.6 Data hiding... 103 4.5.7 Invloed van overerving op de bescherming van leden van een klasse103 4.5.8 Een is een relatie... 104 4.5.9 Beschermende interface via een afgeleide klasse... 104 4.6 Meer dan één afgeleide klasse... 106

4 4.6.1 Schematische voorstelling... 106 4.6.2 Waar komt wat?... 107 4.6.3 Programmavoorbeeld... 107 4.6.4 Constructoren en afgeleide klassen... 109 4.7 Afgeleide klasse van een afgeleide klasse... 110 4.7.1 Schematische voorstelling... 110 4.7.2 Programmavoorbeeld... 110 4.8 Meervoudige overerving (multiple inheritance)... 113 4.8.1 Algemeenheden... 113 4.8.2 Programmavoorbeeld... 114 4.8.3 Ambiguïteit bij meervoudige overerving... 115 4.9 Virtuele basisklasse... 117 4.9.1 Probleem... 117 4.9.2 Programma met tweemaal indirectie overerving van dezelfde klasse117 4.9.3 Oplossing met behulp van een virtuele basisklasse... 119 4.9.3.1 Programma... 119 4.9.3.2 Virtuele basisklasse... 120 4.9.3.3 Schematische voorstelling... 120 4.10 Templates... 121 4.10.1 Definitie... 121 4.10.2 Voorbeeld... 122 4.10.3 Generieke typen... 122 4.10.4 Functietemplate versus preprocessor-macro... 123 4.10.4.1 Voorbeeld met preprocessor-macro... 123 4.10.4.2 Met een functietemplate... 123 4.10.5 Werking van de functietemplate... 124 4.10.6 Klassetemplates... 125 4.10.6.1 Gebruik... 125 4.10.6.2 Programmavoorbeeld... 125 4.11 Oefeningen... 127 5. Polymorfisme en virtuele lidfuncties...128 5.1 Virtuele lidfunctie... 128 5.1.1 Het keyword virtual... 128 5.1.2 Probleem... 128 5.1.3 Voorbeeld van probleemgeval... 128 5.1.4 Virtuele lidfunctie... 131 5.2 Dynamische binding (late binding)... 131 5.2.1 Dynamische binding... 131 5.2.2 Late binding versus vroege binding... 132 5.3 Polymorfisme... 132 5.3.1 Woordverklaring... 132 5.3.2 Gebruik van het concept polymorfisme... 132 5.3.3 Polymorfisme in C++... 132 5.3.4 Voorbeeld... 133 5.3.5 Programmavoorbeeld... 134 5.4 Abstracte basisklasse... 136 5.4.1 Doel en gebruik van een abstracte klasse... 136 5.4.2 Nut van een abstracte klasse... 136 5.4.3 Definitie van een abstracte klasse... 136 5.4.4 Programmavoorbeeld... 137 6. De I/O bibliotheek van C++...140 T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

5 6.1 De isostream bibliotheek... 140 6.2 Het begrip stream... 140 6.3 De verschillende streamklassen... 141 6.3.1 Hiërachie... 141 6.3.2 Soorten streams... 141 6.3.3 Het vereenvoudigd model van iostream... 141 6.4 De ostreamklasse... 142 6.5 De istreamklasse... 143 6.6 De ofstreamklasse... 143 6.6.1 De klasse ofstream... 143 6.6.2 Een nieuw bestand maken... 144 6.6.3 Strings schrijven naar een bestand... 145 6.7 De ifstreamklasse... 146 6.7.1 De klasse ifstream... 146 6.7.2 Een bestand lezen met behulp van een stream... 146 6.7.3 Strings lezen uit een bestand... 147 6.7.3.1 Inlezen van strings met de extraction-operator... 147 6.7.3.2 Probleem met de extraction-operator... 147 6.7.3.3 Strings lezen uit een bestand met getline()... 148 6.7.4 Het testen van een stream... 148 6.7.4.1 Mogelijk optredende fouten... 148 6.7.4.2 Het testen met de naam van de stream... 148 6.7.4.3 De lidfunctie fail()... 149 6.7.4.4 Functies die fouten behandelen... 149 6.8 De strstreamklasse... 150 6.8.1 De lidfuncties str() en freeze()... 150 6.8.2 De manipulator setw en de lidfunctie width()... 150 6.8.3 De manipulator setiosflags... 151 6.8.3.1 Links uitlijnen... 151 6.8.3.2 Rechts uitlijnen... 152 6.8.3.3 Een vast aantal cijfers na het decimale punt... 152 6.8.3.4 Wetenschappelijke notatie... 153 6.8.3.5 Aanvullen van een veld... 153 6.8.3.6 Talstelsels decimaal, hexadecimaal en octaal... 154 6.8.3.7 De manipulator endl... 154 6.8.3.8 De manipulator flush... 155 6.9 Input/Output met objecten... 155 6.9.1 I/O van objecten met behulp van lidfuncties... 155 6.9.2 I/O van objecten met behulp van operatoren... 156 6.9.2.1 Opzet... 156 6.9.2.2 Voorbeeld... 156 6.9.3 Objecten in een bestand... 159 6.9.3.1 Algemeen... 159 6.9.3.2 Schrijven van objecten naar een bestand... 159 6.9.3.3 Lezen van objecten uit een bestand... 160 6.9.3.4 Tegelijk objecten lezen uit en schrijven in een bestand... 161 6.9.4 Random file access... 162 6.9.4.1 Algemeen... 162 6.9.4.2 Beschikbare inputstream functies... 162 6.9.4.3 Beschikbare outputstream lidfuncties... 162 6.9.4.4 Tweede argument van seekg() en seekp()... 163

6 6.10 Allerlei met bestanden... 163 6.10.1 Een stream na de declaratie koppelen aan een bestand... 163 6.10.2 Een bestand sluiten... 163 6.10.3 Toevoegen aan einde bestand... 164 6.10.4 Bestaand bestand openen en leeg maken... 164 6.10.5 Werken met een bestaand bestand... 164 6.10.6 Niet werken met een bestaand bestand... 165 6.11 Binaire bestanden... 165 6.11.1 Binair bestand versus tekstbestand... 165 6.11.2 Schrijven van een object naar een binair bestand... 165 6.11.3 Lezen van een object uit een binair bestand... 167 6.11.4 Lezen en schrijven van objecten via lidfuncties... 168 6.11.5 Bijwerken van een bestand met gebruik van random access... 170 6.12 Kopiëren van een bestand... 171 6.12.1 Kopiëren van een bestand, byte per byte.... 171 6.12.2 Kopiëren van een bestand met rdbuf()... 172 6.12.3 Kopiëren van een bestand naar het beeldscherm... 172 6.12.4 Kopiëren van een bestand naar de printer... 173 6.13 Oefeningen... 173 7. Classes...174 7.1 De MFC-bibliotheek... 174 7.1.1 Algemeen... 174 7.1.2 Groepen klassen... 174 7.2 De CObject-klasse... 175 7.2.1 De CObject-klasse... 175 7.2.2 Basiseigenschappen van de CObject-klasse... 175 7.3 De CFile-klasse... 175 7.3.1 Files... 175 7.3.1.1 De CFile-klasse... 175 7.3.1.2 Afgeleide klassen van CFile... 175 7.3.1.3 Voorbeeld... 176 7.3.2 Serializatie van objecten... 177 7.3.2.1 Serializatie van een object... 177 7.3.2.2 Een klasse serializeerbaar maken... 177 7.3.2.3 Het serializeren van een object... 179 7.4 De CException-klasse... 181 7.4.1 Exceptions... 181 7.4.2 Werking van exception handling... 182 7.4.3 Exception handling met verschillende types... 183 7.4.4 Definiëren van een exceptie in een klasse... 185 7.4.5 Exception-klasse met informatie... 186 7.4.6 Het exception mechanisme... 187 7.4.7 Teruggooien van een reeds opgevangen exceptie... 189 7.4.7.1 Re-throw... 189 7.4.7.2 Voorbeeld... 190 7.4.8 Het voorkomen van geheugenlekken bij excepties... 191 7.4.8.1 Geheugenlekken... 191 7.4.8.2 De catch all instructie... 191 7.5 Containers... 192 7.5.1 Containerklasse... 192 7.5.1.1 Wat is een containerklasse?... 192 T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

7 7.5.1.2 Voorbeeld van containerklasse... 192 7.5.1.3 Containerklasse versus afgeleide klasse... 193 7.5.2 STL-bibliotheek... 194 7.5.2.1 Algemeen... 194 7.5.2.2 Inleiding tot het gebruik van de STL-bibliotheek... 195 7.5.2.3 Lidfuncties van een container... 198 7.5.2.4 De Vector container... 198 7.5.2.5 De List container... 199 7.6 Klassen voor algemeen gebruik... 200 7.6.1 De CTime-klasse... 200 7.6.2 De CString-klasse... 200 7.6.3 Voorbeeld... 201 8. Object georiënteerd ontwerp...202 8.1 Systeem van onderling handelende objecten... 202 8.2 Object georiënteerd ontwerp versus procedureel ontwerp... 203 8.3 Stappen in een object georiënteerde aanpak... 203 8.3.1 Identificatie van de klassen... 204 8.3.2 Hiërarchie van de klassen... 204 8.3.3 Interface van de klassen... 204 8.3.4 Programmatie van de klassen... 205 8.3.5 Schrijven van het hoofdprogramma... 205 8.4 Constructie van correcte klassen... 205 8.5 Voordelen van het aanwenden van OOP... 206 8.6 Een op data gerichte aanpak... 207 8.6.1 Data abstractie... 207 8.6.2 Encapsulatie... 208 8.6.3 Inheritance... 208 8.6.4 Polymorfisme en dynamische binding... 209 8.6.5 Besluit... 209

8 1. Uitbreidingen en verbeteringen in C++ t.o.v. C 1.1 Inleiding Het succes van C++ als programmeertaal is voor een groot stuk te wijten aan de opkomst van GUI systemen (Graphical User Interface), zoals bv. Windows. Het programmeren in een GUI-systeem vraagt de manipulatie van velerlei objecten, zoals vensters, menu s, knoppen, enz. Bovendien is een GUI event driven. Dit betekent dat een bepaald object slechts geactiveerd wordt als er een bericht naar toe gestuurd wordt, zoals bv. een muisklik. Dit zijn allemaal aspecten die in object georiënteerd programmeren aan bod komen. Zodoende zal een OOP-taal, zoals C++, praktisch noodzakelijk zijn in dergelijke omgevingen. Bovendien worden de besturingsystemen qua opbouw meer en meer object georiënteerd. Zo is Windows NT een typisch object georiënteerd systeem, waarin alle elementen van het besturingsysteem als objecten worden gehandeld, nl. de user-interface, de disk-interface en netwerk-interface. Een interessant aspect van de C++ taal is het feit dat ze volledig gebaseerd is op de C-taal. C++ laat toe om object georiënteerd te programmeren zonder de opgedane ervaring in het programmeren in C te verlaten. In dit deel willen we de verschillende uitbreidingen en verberingen van C++ aanhalen t.o.v. C, die niet rechtstreeks te maken hebben met de filosofie van object georiënteerd programmeren. Deze uitbreidingen en verbeteringen zijn dikwijls wel wenselijk om het toevoegen van object georiënteerde principes mogelijk te maken. We kunnen zeggen dat deze uitbreidingen de noodzakelijke steunpilaren zijn waarop de C++ taal rust. Tevens zijn vele verbeteringen aangebracht om het programmeren veiliger en meer bugvrij te maken. 1.2 Het gebruik van de iostream bibliotheek 1.2.1 In- en uitvoer C++ kent een totaal nieuwe manier van werken met in- en uitvoer. Hiervoor zijn ook nieuwe headerfiles beschikbaar. De vertrouwde C-functies blijven evenwel beschikbaar, doch het mengen van beide moet worden afgeraden. De standaard in- en uitvoer bibliotheek van C++ is de iostream bibliotheek. 1.2.2 De iostream bibliotheek 1.2.2.1 Algemeen De iostream bibliotheek is de input/output bibliotheek die standaard bijgeleverd is met de C++ compiler. Deze bibliotheek maakt input en output naar het scherm, naar files en naar geheugen mogelijk. De iostream bibliotheek vervangt de stdio bibliotheek van C. T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

9 De iostream bibliotheek is niet ingebouwd in de C++ taal zelf, maar vormt een aparte klassen-bibliotheek. Het voordeel van de iostream bibliotheek is het feit dat ze gebruik maakt van alle C++ eigenschappen. Dit betekent dat we input en output operaties kunnen laten verlopen via operatoren. Bovendien kunnen we, indien noodzakelijk, de functionaliteit van de iostream bibliotheek aan onze eigen wensen aanpassen door gebruik te maken van afgeleide klassen. 1.2.2.2 Het begrip stream We kunnen een stream beschouwen als een equivalent van een input/output device. Als dusdanig representeert een stream altijd een medium, waarnaar we input/output operaties uitvoeren. In C++ is een stream een object, behorend tot een specifieke streamklasse. De karakteristieken van het stream-object worden bepaald door de klasse waartoe het behoort, en door de eigen toevoegingen aan deze klasse. 1.2.2.3 De verschillende streamklassen Er zijn zes belangrijke streamklassen: istream klasse die input verzorgt afkomstig van het toetsenbord ostream klasse die output verzorgt naar het scherm ifstream klasse die input verzorgt afkomstig van files ofstream klasse die output verzorgt naar files istrstream klasse die intput verzorgt afkomstig van het geheugen ostrstream klasse die output verzorgt naar het geheugen Daarbij is er nog de iostream klasse, die afgeleid is uit de klassen istream en ostream. 1.2.3 Uitvoer De standaard outputstream noemt cout. Gegevens naar de output sturen gebeurt met de insertion operator <<. Voorbeeldprogramma. /* programma P110.cpp */ #include <iostream.h> char c= A ; float f= 12.57; cout << Hello, world.\n ; cout << c = << c << \n ; cout << f = << f << \n ; Dit kleine programma bevat de twee belangrijkste bouwstenen van de C++ taal: het object en de operator. Het object is cout, dat de standaard output representeert. De standaard output is het beeldscherm. Met andere woorden, cout representeert het beeldscherm.

10 De operator is <<, die gebruikt wordt om gegevens naar de standaard output te sturen. Merk op dat in tegenstelling tot de functie printf() het in C++ niet nodig is om te specificeren dat een string, of een integer, of een karakter of een float moet worden uitgeprint op het scherm. De uitvoering van de operator << verschilt naargelang de operator inwerkt op een string, of op een integer, of op een karakter of op een float. 1.2.4 Invoer De standaard inputstream noemt cin. De standaard input is het toetsenbord. Met andere woorde, cin representeert het toetsenbord. Gegevens lezen van de input gebeurt met de extraction operator >>. Voorbeeldprogramma. /* programma P111.cpp */ #include <iostream.h> char c; float f; char sr[30]; cout << Typ een letter in: \n ; cin >> c; cout << Typ een gebroken getal in: \n ; cin >> f; cout << Typ een string in: \n ; cin >> s; cout<< De ingevoerde letter is << c <<endl; cout<< Het ingevoerde getal is << f <<endl; cout<< De ingevoerde string is << s <<endl; Ook bij cin moet het type van de in te voeren variabele niet worden meegegeven. 1.2.5 I/O manipulatoren 1.2.5.1 Opmaak van getallen Met de manipulatoren dec, hex en oct kan een getal worden weergegeven in respectievelijk decimaal, octaal en hexadecimaal formaat. De functie setbase(int n) bepaalt het talstelsel voor de weergave van het eerst volgende getal. De waarde van n bepaalt het talstelsel: n= 0 (default) : 10-tallig stelsel n= 8 : 8-tallig stelsel n= 10 : 10-tallig stelsel n= 16 : 16-tallig stelsel T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

11 De functie setprecision(int n) bepaalt het aantal decimalen bij floating point getallen. /* programma P112.cpp */ #include <iostream.h> #include <iomanip.h> int i; i= 16; cout << dec << i << endl; // 16 cout << oct << i << endl; // 20 cout << hex << i << endl; // 10 cout << setbase(16) << 16 << \t << 16 << endl; // 10 16 cout << setprecision(4) << 3.1415926535 << endl; // 3.1415 1.2.5.2 Algemene opmaak endl setw(int n) setfill(int n) vervangt \n dient om de breedte van een veld op te geven dient om het opvulkarakter aan te geven bij gebruik van setw() /* programma P113.cpp */ #include <iostream.h> #include <iomanip.h> cout << Hello world << endl; cout << setw(8) << setfill( # ) << 45 << endl; 1.2.5.3 Uitlijnen Volgend programma lijnt de eerste uit te printen kolom links uit en de tweede kolom wordt rechts uitgelijnd. /* programma P114.cpp */ #include <iostream.h> #include <iomanip.h> double waarden[] = 1.36, 45.14, 8.124, 4589.44568 char *namen[] = Els, Jef, Ria, Jan ; for (int i= 0; i < 4; i++) cout << setiosflags(ios::left) << setw(6) << namen[i] << resetiosflags(ios::right) << setw(10) << waarden[i] << endl;

12 1.3 Het plaatsen van de declaraties van variabelen In C kan een declaratie van een variabele slechts gebeuren aan het begin van een blok. Een blok is hier de verzameling code binnen de accolades. In C++ is het mogelijk een declaratie te schrijven gelijk waar in een blok. Een variabele moet dus niet vooraan in een blok gedeclareerd worden. De variabele is gekend van de regel van declaratie tot het einde van de scope. Voor een lokale variabele is dat tot het einde van het blok. Voor een globale variabele is dat tot het einde van het programma. Zo is het volgende toegelaten: double ds1 = sin(1.0); ds1 *= 2; double ds2 = cos(1.0); ds2 *= 2; Deze eigenschap wordt veel gebruikt in for-loops: for (int i= 0; i < 10; i++) // code Echter is een declaratie niet toegelaten in een stuk code dat slechts conditioneel kan uitgevoerd worden: if (x < 10) int y = 20; //fout else int y = 10; //fout Voorbeeld van scope: main() // x is niet gekend // i is niet gekend // j is niet gekend int x; // x is gekend // i is niet gekend // j is niet gekend T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

13 for (int i= 0; i < 32767; i++) // x is gekend // i is gekend // j is niet gekend int j; // x is gekend // i is gekend // j is gekend // x is gekend // i is niet gekend // j is niet gekend 1.4 Typeconversie 1.4.1 Converteren In C++ plaatst men de te converteren expressie tussen haakjes, zodat dit lijkt op een functie-oproep. De conversie waarbij het type tussen haakjes staat, blijft ook bruikbaar. int i; char c; i = (int) c; // C notatie i = int (c); // C++ notatie 1.4.2 Typedef In C zijn er twee manieren om met een struct te werken. 1) struct a ; ; struct a var1; // dit vraagt veel typwerk bij gebruik van struct 2) typedef struct struct_a ; a; a var1; // dit vraagt minder typwerk bij gebruik van struct, maar de // definitie is zwaar In C++ kan het keyword struct weggelaten worden bij de definitie van variabelen van een bepaald type struct. struct a ; ; a var1; // dit vraagt het minst typwerk

14 1.5 Het type const 1.5.1 Het const type Met het type const wordt een variabele gedeclareerd waarvan de waarde constant moet blijven gedurende de hele uitvoering van het programma. De compiler waakt erover dat zo n variabele geen nieuwe waarde toegekend wordt. In plaats van #define MAXITEMS 10 kan in C++ het volgende: const int MAXITEMS 10; Het voordeel van de nieuwe schrijfwijze t.o.v. de oude is het feit dat het type, in het voorbeeld int, expliciet geverifieerd wordt telkens de variabele wordt gebruikt. const int GROOTTE 30; GROOTTE = 40; // compiler genereert een fout 1.5.2 Expressies De expressie const int *pci; declareert een pointer die verwijst naar een const int. Dit betekent dat aan pci wel vrij een adres kan worden toegekend, maar pci verwijst telkens naar een niet te veranderen waarde. Dus: const int d = 3; pci = &d; // OK *pci = 3; // FOUT In volgend programmavoorbeeld wordt de pointer p gedeclareerd naar een const int. Dit betekent dat aan de variabele p wel vrij een adres kan worden toegekend, doch dat p telkens wijst naar een niet te veranderen waarde. /* programma P115.cpp */ #include <iostream.h> const int a= 5, b= 10; const int *p= &a; cout<< Inhoud van p: << (void *)p << endl; cout<< p wijst aan : << *p << endl; p= &b; // ander vrij adres cout<< Inhoud van p: << (void *)p << endl; cout<< p wijst aan : << *p << endl; T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

15 De expressie int i; int *const cpi = &i; declareert de constante pointer cpi naar een integer. Deze pointer cpi kan naar niets anders wijzen, maar hetgeen de pointer cpi aanwijst kan wel veranderd worden. Volgend programma declareert een constante pointer p naar een int. De pointer p kan naar niets anders wijzen, maar hetgeen p aanwijst kan wel worden gewijzigd. Dit is een belangrijk verschil met de definitie van p in vorig programma. /* programma P116.cpp */ #include <iostream.h> int a= 5, b= 10; int *const p= &a; cout<< Inhoud van p: << (void *)p << endl; cout<< p wijst aan : << *p << endl; a= 10; // p wijst andere waarde aan cout<< Inhoud van p: << (void *)p << endl; cout<< p wijst aan : << *p << endl; Men kan const ook gebruiken bij het declareren van een functie om te beletten dat de functie één van zijn parameters zou wijzigen. Veronderstel het volgende prototype: int readonly(const struct Astruct *AreadonlyStruct); Dit prototype belet dat de structuur waarnaar AreadonlyStruct verwijst gewijzigd kan worden. Wil de programmeur dit toch doen, dan genereert de compiler een fout, zoals in volgend voorbeeld: int readonly(const struct Astruct *AreadonlyStruct) AreadonlyStruct -> element = 3; //compiler genereert fout 1.6 Het type referentie 1.6.1 Probleem Het volgend programma illustreert een probleem dat kan voorkomen bij het toekennen van een waarde aan de parameters van een functie op basis van doorgeven van waarde (call by value). Telkens de functie opgeroepen wordt, worden de waarden van de doorgegeven parameters gekopieerd in de lokale parameters van de functie. Het resultaat hiervan is dat, wanneer een doorgegeven parameter wordt gewijzigd, we die wijziging niet terugzien in de aanroepende functie.

16 /* programma P117.cpp */ #include <iostream.h> void increment(int); int i= 3; cout<< i = << i << endl; // i = 3 increment(i); cout<< i = << i << endl; // i = 3 void increment(int i) i++; Het programma geeft als resultaat 3, alhoewel increment(i) de variabele i lokaal heeft gewijzigd in 4. Wanneer de programmeur wenst dat een functie een aantal parameters moet wijzigen, dan moet de programmeur een pointer doorgeven naar die functie (call by address), zoals getoond in volgend programma. /* programma P118.cpp */ #include <iostream.h> void increment(int *); int i= 3; cout<< i = << i << endl; // i = 3 increment(&i); cout<< i = << i << endl; // i = 4 void increment(int* pi) (*pi)++; // () zijn nodig omdat ++ voorrang heeft op * Het vervelende aan bovenstaande constructie is dat expliciet een pointer moet worden doorgegeven aan de functie met behulp van de adres van operator &, en dat telkens de dereferentie operator * moet worden aangewend binnen de functie om bewerkingen te kunnen uitvoeren met de waarden waarnaar de pointer verwijst. T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

17 1.6.2 Het type referentie 1.6.2.1 Het referentie datatype C++ lost vorig probleem op met het referentie datatype. Eens gedeclareerd zal een referentie fungeren als een alias (een alternatieve naam). Met andere woorden, een referentie gedraagt zich precies zoals de variabele waarnaar hij refereert. Een referentie-variabele is dus een alias voor de variabele waarnaar hij refereert, m.a.w. een referentie is een alternatieve naam voor een variabele. Bewerkingen op een referentie refereren altijd naar de gerefereerde variabele. De unaire & operator indentificeert een referentie. Referenties (E: references) worden het meest gebruikt als parameter. Het voordeel is dat geen data getransfereerd wordt zoals bij call by value, en dat het veiliger is dan een call by address. Referenties kunnen worden gebruikt om meer dan één waarde uit een functie terug te geven, waar in C pointers voor nodig zijn. 1.6.2.2 Programmavoorbeeld Volgend programma maakt gebruik van een referentie. /* programma P119.cpp */ #include <iostream.h> int i, *pi; int &ri = i; // ri is een referentie naar i, geen &i nodig i = 5; // gebruik van i via zijn naam cout<< waarde van i via zijn naam: << i << endl; cout<< adres van i: <<&i << endl; ri = 10; // gebruik van i via zijn referentie cout<< waarde van i via zijn referentie: << i << endl; // i= 10 int j= ri; // j krijgt de waarde van i, nl. j= 10 cout<< waarde van j: << j << endl; ri++; cout<< waarde van i: << i << endl; // i= 11 pi = &ri; // pi bevat het adres van i cout<< inhoud van pi: << pi << endl; In dit programma is ri een alias voor i. Het maakt geen verschil uit of we i of ri gebruiken bij bewerkingen. Echter is een referentie geen kopie van de variabele waarnaar hij verwijst. Het is wel dezelfde variabele onder een andere naam. 1.6.3 Initialisatie van een referentie Een referentie kan niet bestaan zonder een variabele waarnaar gerefereerd wordt. Volgende code kan dus niet: int &refint; // fout

18 De uitzondering op de regel is wanneer bijvoorbeeld een referentie wordt gedefinieerd als parameter van een functie. Met andere woorden, een reference moet steeds geïnitialiseerd worden bij declaratie, behalve als de referentie als parameter wordt gebruikt. In het volgend programma wordt geen return gebruikt. Merk op dat geen return nodig is om i en ri een nieuwe waarde te geven. /* programma P120.cpp */ #include <iostream.h> void increment(int &); int i= 3; //int &ri; //fout: ri : references must be initialized int &ri= i; // declaratie van de referentie ri cout<< i = << i << endl; // i = 3 cout<< ri = << ri << endl; // ri = 3 increment(ri); // referentie wordt doorgegeven cout<< i = << i << endl; // i = 4, nieuwe waarde uit increment() cout<< ri = << ri << endl; //ri = 4, nieuwe waarde uit increment() //cout<< ra= << ra << endl; //fout: ra :undeclared identifier void increment(int &ra) // declaratie van ra zonder initialisatie ra++; cout<< ra= << ra << endl; // ra= 4 1.6.4 Referentie als functieparameter Het referentie datatype is vooral interessant bij het doorgeven van te veranderen parameters naar een procedure. /* programma P121.cpp */ #include <iostream.h> void increment(int &); int i= 3; int &ri= i; // declaratie van de referentie ri cout<< i = << i << endl; // i = 3 cout<< ri = << ri << endl; // ri = 3 increment(ri); // referentie wordt doorgegeven cout<< i = << i << endl; // i = 4 cout<< ri = << ri << endl; // ri = 4 void increment(int &ri) ri++; T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

19 1.6.5 Verschil tussen pointer en referentie Een referentie is eigenlijk niets anders dan een constante pointer, die we kunnen gebruiken zonder dereferentie operator. Zo kan vorig programma P120 geschreven worden met een constante pointer. /* programma P122.cpp */ #include <iostream.h> int i= 3; int *const ri= &i; // ri is een constante pointer naar i cout<< i = << i << endl; // i= 3 cout<< ri = << ri << endl; // adres van de geheugenplaats van ri cout<< *ri = << *ri << endl; // 3 increment(ri); // pointer ri wordt doorgegeven cout<< i = << i << endl; // i= 4 cout<< ri = << ri << endl; // adres van de geheugenplaats van ri cout<< *ri = << *ri << endl; // 4 void increment(int *ri) *ri++; Bemerk echter dat een referentie niet kan behandeld worden als een pointer. Een aantal zaken zijn niet mogelijk met een referentie, terwijl die wel mogelijk zijn met een pointer. 1) Het adres nemen van een referentie kan. /* programma P123.cpp */ #include <iostream.h> int i= 3; int &ri= i; // declaratie van de referentie ri cout<< ri = << ri << endl; // ri = 3 cout<< adres van ri= << &ri << endl; int *pi; pi= π // het adres van pi wordt toegekend aan pi cout<< adres van ri= << pi << endl; (*pi)++; cout<< i = << i << endl; cout<< ri = << ri << endl;

20 2) Een referentie toekennen met een waarde kan niet. /* programma P124.cpp */ #include <iostream.h> int i= 3; //int &ri= 5; // een referentie toekennen met een waarde // fout: initializing : cannot convert from const int to int & int &ri = i; cout<< ri = << ri << endl; // ri= 3 ri= 5; // dit kan wel cout<< i = << i << endl; // i= 5 cout<< ri = << ri << endl; // ri= 5 3) Twee referenties vergelijken met elkaar kan. /* programma P125.cpp */ #include <iostream.h> int i1= 3, i2= 5; int &ri1= i1; int &ri2= i2; if (ri1 == ri2) cout<< gelijk <<endl; else cout<< ongelijk <<endl; cout<<endl; if (ri1 > ri2) cout<< ri1 <<endl; else cout<< ri2 <<endl; 4) Twee referenties optellen kan. /* programma P126.cpp */ #include <iostream.h> int i1= 3, i2= 5; int &ri1= i1; int &ri2= i2; cout<< ri1 + ri2 = << ri1+ri2 << endl; T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

21 5) Enkel een referentie aan een constant object kan geïnitialiseerd worden met een rvalue of met een lvalue van een ander type. /* programma P127.cpp */ #include <iostream.h> int i= 1; double dl1= 2.3, dl2= 10.5; // int &ri= 5; // fout: initializing : cannot convert from // const int to int &, m.a.w. geen lvalue // double &rdl1= i; // fout: initializing : cannot convert from // int to double &, m.a.w. 2 verschillende types // double &rdl= dl1 + dl2; // fout: geen lvalue const int &ri= 5; // initialisatie met een rvalue cout<< ri= << ri << endl; // ri= 5 const double &rdl1= i; // initialisatie met een lvalue van een ander type cout<< rdl1= << rdl1 << endl; // rdl1= 1 const double &rdl= dl1 + dl2; // toegelaten cout<< rdl= << dl1 + dl2<< endl; // rdl= 12.8 6) Een referentie wijzigen kan niet. /* programma P128.cpp */ #include <iostream.h> int i1= 3, i2= 5; int &ri1= i1; //int &ri1= i2; //fout: ri1 : redefinition; multiple initialization cout<< ri1 = << ri1 << endl; 7) Het is mogelijk een referentie (in het voorbeeld de referentie r1), die de formele parameter is van een functie (in het voorbeeld van de functie f1), opnieuw door te geven als actuele parameter (in het voorbeeld de actuele parameter r1 van de functie f2(r1) naar een functie waar de formele parameter opnieuw een referentie is (in het voorbeeld naar de functie f2(int &r2) waar de formele parameter r2 een referentie is). /* programma P129.cpp */ #include <iostream.h> void f2(int &r2) r2*=2;

22 void f1(int &r1) f2(r1); int i= 7; f1(i); cout<< i = << i << endl; // i= 4 1.6.6 Referenties als terugkeerwaarde Naast het doorgeven van parameters naar een functie, kunnen referenties ook gebruikt worden voor het teruggeven van waarden door een functie. In het volgende programma geeft de functie num() een referentie terug aan EenNummer. We kunnen zeggen dat num() als een alias fungeert voor EenNummer. Met andere woorden, we krijgen hetzelfde resultaat als in main() de functie num() vervangen wordt door EenNummer. /* programma P130.cpp */ #include <iostream.h> int EenNummer= 0; int &num() return EenNummer; int i; i= num(); num() = 5; Functies die een referentie terug geven kunnen als lvalue gebruikt worden, zoals getoond in volgend programma. De functie min(i1, i2) wordt als lvalue gebruikt in min(i1, i2) = min(i1, i2) * 3. Concreet wordt de opdracht: i1= 10 * 3. /* programma P131.cpp */ #include <iostream.h> int &min(int &ri1, int &ri2) return(ri1 < ri2? ri1 : ri2); // ri1 refereert naar i1, waardoor i1 blijft // bestaan als de functie is afgelopen T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

23 int i1= 10, i2= 20; min(i1, i2)*= 3; //het kleinste getal wordt vermenigvuldigd met 3 cout<< i1= << i1 << endl; // i1= 30 cout<< i2= << i2 << endl; // i1= 20 1.7 Initialisatie van variabelen Initialisatie is het initieel toekennen van een waarde van een variabele. De variabele krijgt een beginwaarde. Initialiseren gebeurt telkens bij het declareren van de variabele. De syntax voor de initialisatie van een variabele is gevoelig verbeterd in C++ tenopzichte van C. 1) Een eerste verbetering is de mogelijkheid om een variabele te intitialiseren met behulp van een volledige expressie in plaats van met een constante expressie, zoals getoond in volgende code: const double pi = acos(-1.0); const double e = exp(1.0); 2) Een andere verbetering t.o.v. C is de mogelijkheid om de initialisatie te schrijven met behulp van haakjes. Volgende C-code int i = 0; double x = 1.0; kan in C++ als volgt: int i(0); double x(1.0); Deze schrijfwijze is vooral nuttig wanneer men klassen wil initialiseren via hun constructor, zoals Complex c(1.0, 2.0); evenals: Complex c = Complex(1.0, 2.0); 3) Een volgende verbetering is de specificatie van een cast. Waar in C een cast wordt gespecificeerd door volgende code: int i; double d; d = (double) i; kan die in C++ vervangen worden door: int i; double d; d = double( i);

24 1.8 Overloaded functies 1.8.1 Overloading Een veel voorkomend geval is dat de programmeur functies schrijft die hetzelfde uitvoeren, maar die een verschillend aantal argumenten of een verschillend type argumenten aanvaarden. In C is het noodzakelijk om deze functies een verschillende naam toe te kennen. Zo zal volgende notatie noodzakelijk zijn: Complex_i(int x, int y); Complex_d(double x, double y); Complex_c(struct complex c); In C++ is het echter toegelaten hiervoor dezelfde functie-namen te gebruiken. Dit is overloading van functies. Voorwaarde is wel dat de functies onderscheiden kunnen worden door een verschillend aantal argumenten, of door een verschillend type van argumenten. Het vorig voorbeeld kan dus herschreven worden als: Complex(int x, int y); Complex (double x, double y); Complex (struct complex c); Bij een aanroep van Complex() zal de compiler die versie van Complex() oproepen die dezelfde types van parameters heeft als de aanroep. Complex(3, 4); // roept Complex(int x, int y) op Complex(4.2, 6.5); // roept Complex(double x, double y) op Wanneer er geen exacte overeenkomst van parameters is, dan gelden de standaard conversie-regels voor het vinden van een overeenstemmende routine. Soms levert dit dubbelzinnige situaties op, zoals in volgend voorbeeld: Complex((long) 3, (long) 4); // fout De compiler geeft de fout: ambiguous call to overloaded function, omdat zowel Complex(double x, double y) als Complex(int x, int y) kan worden gebruikt. Dit levert een ambigue (dubbelzinnige, tweeslachtige) situatie op. De compiler weet niet wat gedaan. In C++ zijn twee functies verschillend als hun namen verschillen of als hun aantal parameters verschillen, of als de types in een andere volgorde staan. Dit betekent dat de functie abx(int) en de functie abs(float) twee verschillende functies zijn. Het returntype is niet van belang om te bepalen of een functie-declaratie reeds voorkomt. Bijgevolg zijn int random(void) en float random(void) dezelfde functies en dit levert een compiler-fout op. T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

25 1.8.2 Gebruik Overloading kan het programmeren aanzienlijk vereenvoudigen, zoals getoond in volgend programma. /* programma P132.cpp */ #include <iostream.h> int square(int r) return ( r >= -250 && r <= 250)? r*r : -1; long square(long r) return ( r >= -40263 && r <= 40263)? r*r : -1; void main(void) int i= 20; long lg= 1064; cout<< i kwadraat = <<square(i)<<endl; cout<< lg kwadraat = <<square(lg)<<endl; 1.8.3 Functie aanroepen met argumenten van verschillend type 1.8.3.1 Voorbeeld met automatische convertie /* programma P132.cpp */ #include <iostream.h> void demo(double); void main(void) demo(10); demo(5.24); //automatische conversie van int naar double void demo(double a) cout<< a << is een double. << endl; Resultaat: 10 is een double. 5.24 is een double.

26 1.8.3.2 Voorbeeld met verlies van data /* programma P133.cpp */ #include <iostream.h> void demo(int); void main(void) demo(10); demo(5.24); //warning: argument :conversion from const double to int //possible loss of data void demo(int a) cout<< a << is een int. << endl; Resultaat: 10 is een int. 5 is een int. // verlies van data 1.9 Type-safe linken 1.9.1 Probleem Alhoewel men in C++ verplicht is om een prototype mee te geven bij het aanroepen van een functie, bestaan er toch situaties waarbij de compiler niet kan garanderen dat de correcte argumenten worden doorgegeven aan de aangeroepen functie. Veronderstel bijvoorbeeld dat een bibliotheekfunctie wordt aangeroepen en dat het prototype, meegegeven in het programma, andere types argumenten specificeert dan de bibliotheekfunctie verwacht. Doordat de compiler geen weet heeft van de juiste structuur van de bibliotheekfunctie, zal verkeerde code worden gegenereerd. Bovendien rijst het probleem van overloaded functies. Immers, overloaded functies hebben dezelfde functienaam, maar een verschillend type argumenten. De oplossing voor die problemen is het aanwenden van een type-safe linken procedure. 1.9.2 Type-safe linken Type-safe linken is een systeem dat garandeert dat functies gelabeld worden met informatie betreffende de argument-types, zodat bij het linken de correcte functies worden aangeroepen. Concreet betekent dit dat de compiler de naam van de functie intern zal omvormen tot een nieuwe naam, die de informatie bevat betreffende het type argumenten. Bij het linken wordt dan die interne naam gebruikt om de functie in kweste te koppelen aan de functie die in de bibliotheek voorkomt. Wanneer dan de programmeur een fout maakt in het specificeren van het prototype, zal tijdens het linken een fout T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

27 worden gegenereerd, die zegt dat de bedoelde functie met dit type van argumenten niet kan teruggevonden worden in de bibliotheek. Type-safe linken garandeert echter niet dat de functie-terugkeertypes correct zijn, of dat extern gerefereerde variabelen van de correcte types zijn. Voorbeeld: #include<math.h> double afstand(double x1, double y1, double x2, double y2) double d1 =x2 x1; double d2 = y2 y1; In een andere file wordt de functie afstand() op de volgende manier opgeroepen: #include<stdio.h> extern int afstand(double, double, double, double); prinft( %d\n, afstand(1.0, 1.0, 2.0, 2.0); De code in de main() zal nonsens teruggeven omdat het prototype voor afstand() liegt betreffende het returntype. De compiler kan de fout niet ontdekken omdat de functie extern gedeclareerd wordt. Ook zal de linker geen fout geven omdat het type-safe linken niet in staat is om het returntype te verifiëren. Het probleem ligt bij het extern declareren van functies en/of variabelen direct in functies. Externe declaraties horen thuis in header files en niet rechtstreeks in de source files. 1.10 Inline functies 1.10.1 Inline specifier en inline functie Een inline functie is een functie die begint met de inline specifier, zoals bijvoorbeeld: inline MAX(int getal1, int getal2). De inline specifier wordt ook inline specificator genoemd. Het sleutelwoord (E: keyword) inline kenmerkt de functie voor inline expansie, nl. een inline functie wordt op de plaats van de aanroep door de compiler tot de functie-body geëxpandeerd. 1.10.2 Functie versus macro Een groot nadeel van een functie is dat ze traag werkt. Immers, bij gebruik van de functie MAX(int getal1, int getal2) moeten de twee argumenten worden gekopieerd, moeten machineregisters worden opgeslagen en moet het programma op een nieuwe locatie instructies selecteren. In plaats van de functie grootste = MAX(10, 50) op te roepen, is de handmatige code grootste = (a > b)? a : b; gewoon sneller.

28 Een macro wordt wel in de code gevoegd. Een macro werkt dus als de handmatige code, maar bij gebruik van een macro worden de argumenten vervangen door hun waarde, en dit kan leiden tot fouten. Volgend programma bepaalt het grootste van twee getallen met behulp van een macro. Waar in C veel gebruik wordt gemaakt van macro s om korte functies rechtstreeks als code in te voegen in de source file, dit om een expliciete aanroep van een functie te vermijden en dus de snelheid van uitvoering op te drijven, geeft dit soms aanleiding tot problemen, zoals in volgend voorbeeld. /* programma P134.cpp */ #include <iostream.h> #define MAX(getal1, getal2)((getal1>getal2)?getal1:getal2) //macro int grootste; grootste = MAX(10, 50); cout<< Grootste getal is << grootste << endl; // 50 cout<<endl; int getal2 = 50; grootste = MAX(10, getal2++); cout<< Grootste getal is << grootste << endl; // 51 In het tweede geval is de waarde van grootste niet juist (het moet 50 zijn). Dit komt omdat de code als volgt werd geëxpandeerd: grootste= ((10 > 51)? 10 : 51) Om functies te expanderen tot gewone code in een programma en dit op een veilige manier, laat C++ toe inline functies te gebruiken, zoals in volgend programma. /* programma P135.cpp */ #include <iostream.h> inline MAX(int, int); //prototype van de inline functie int grootste; grootste = MAX(10, 50); cout<< Grootste getal is << grootste << endl; // 50 cout<<endl; int getal2 = 50; grootste = MAX(10, getal2++); cout<< Grootste getal is << grootste << endl; // 50 inline MAX(int getal1, int getal2) // inline functie return (getal1 > getal2)? getal1 : getal2; T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

29 Het stukje code grootste = MAX(10, getal2++) wordt nu geëxpandeerd tot: int temp1= 10; int temp2 = getal2++; grootste = temp1 > temp2? temp1 : temp2; Bij int temp2 = getal2++; wordt eerst de inhoud van getal2 toegekend aan temp2 en pas daarna wordt de inhoud van getal2 met 1 verhoogd. 1.10.3 Vraag aan de compiler De inline specifier expandeert niet altijd een functie. De inline specifier fungeert alleen als een hint voor de compiler. De compiler kan kiezen om de functie niet te expanderen, afhankelijk van het nut, bv. wanneer de inline functie te veel regels code bevat zodat het nut ervan teniet gedaan wordt, of in bepaalde omstandigheden waarin de compiler niet kan expanderen. Een inline functie wordt niet geëxpandeerd als die recursief gedefinieerd is, of wanneer een pointer naar de functie genomen wordt. In het volgende voorbeeld zal de eerste aanroep van MAX() geëxpandeerd worden, de tweede niet. int (*p) (int a, int b); int x = MAX(3, 5); //MAX wordt geëxpandeerd p= MAX; // p krijgt het adres van de functie MAX() int y = p(3, 5); //MAX() wordt niet geëxpandeerd omdat de //pointer p naar MAX() is opgenomen in het //programma 1.11 Default functie-argumenten 1.11.1 Default functie-argumenten Default functie-argumenten betekent dat een functie een default waarde heeft voor argumenten, die niet expliciet geïnitialiseerd worden. Volgende functiedefinitie bevat een default waarde voor de argumenten x2 en y2, die niet expliciet in main() zijn geïnitialiseerd: double distance(double x1, double y1, double x2= 0, double y2= 0) De default argumenten moeten op het einde van de functiedefinitie worden geplaatst. C++ voorziet de mogelijkheid om bij de aanroep van een functie minder argumenten mee te geven dan het aantal parameters bedraagt. In dat geval moeten in de functiedefinitie de default waarden van die argumenten zijn

30 opgenomen. De default argumenten worden gebruikt bij een functieoproep als de daarop volgende argumenten ontbreken. Naast de directe specificatie van de default argumenten in de functiedefinitie is het ook mogelijk om de default argumenten te specificeren in het functieprototype, maar dan moet de functiedefinitie zonder default argumenten worden genoteerd. 1.11.2 Voorbeeld In volgend programma wordt de afstand berekend tussen twee punten. Indien de coördinaten van het tweede punt niet worden meegegeven naar de functie, wordt de afstand berekend t.o.v. het nulpunt. /* programma P136.cpp */ #include <iostream.h> #include <math.h> double afstand(double x1, double y1, double x2= 0, double y2= 0) double d1= x2 x1; double d2 = y2 y1; return sqrt(d1*d1 + d2*d2); //sqrt()= square root (vierkantswortel) // en vereist math.h double afstand1 = afstand(2, 8); //x1=2, y1=8, x2=0, y2=0 cout<< afstand1= << afstand1 << endl; //afstand1= 8.24621 double afstand2 = afstand(5,9,2,5); //x1=5, y1=9, x2=2, y2=5 cout<< afstand2= << afstand2 << endl; //afstand2= 5 Wanneer een waarde wordt meegegeven voor x2 en y2, dan worden die waarden gebruikt, anders worden x2 en y2 geïntialiseerd op 0. In het opgegeven programma moet minstens twee argumenten worden meegegeven aan de functie. De default waarden moeten altijd op het einde worden geplaatst. 1.11.3 Default argumenten en functie-overloading Volgend programma toont hoe bij de oproep van de functie lijn(), de default argumenten worden aangewend wanneer in de oproepende code de daaropvolgende argumenten ontbreken. Bij lijn() ontbreken de twee argumenten. De eerste default argumentwaarde is het karakter - voor het argument c, en de tweede default argumentwaarde is de waarde 80 voor het argument i. Bij lijn( = ) ontbreekt het tweede argument, dat de default waarde 80 krijgt. Merk op dat de argumentwaarde van de oproepende code de bovenhand haalt op de default argumentwaarde. Bij lijn( =, 20) krijgen de twee argumenten een waarde van de oproepende code. T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc

31 Bij lijn(30) treedt er een fout op omdat de doorgegeven argumentwaarde, nl. de getalwaarde 30, niet kan worden toegekend aan het argument char c. /* programma P137.cpp */ #include <iostream.h> void lijn(char c= -, int i= 80) for (int t= 1; t<=i; t++) cout<< c; cout<< endl; lijn(); // afdruk van 80 keer het karakter - lijn( = ); // afdruk van 80 keer het karakter = lijn( =, 20); // afdruk van 20 keer het karakter = lijn(30); // levert foutief resultaat op Met functie-overloading van de functie lijn() met een functie die een integer aanvaardt als parameter, is het foutief resultaat van vorig programma ongedaan gemaakt, en worden alle combinaties mogelijk. /* programma P138.cpp */ #include <iostream.h> void lijn(char c= -, int i= 80) for (int t= 1; t<=i; t++) cout<< c; cout<< endl; void lijn(int i) for (int t= 1; t<=i; t++) cout<< # ; cout<< endl; lijn(); // afdruk van 80 keer het karakter - lijn( = ); // afdruk van 80 keer het karakter = lijn( =, 20); // afdruk van 20 keer het karakter = lijn(30); // afdruk van 30 keer het karakter #

32 1.11.4 Wat kan met functie-overloading en default argumenten? Stel de functie: lijn(char c= -, int i= 80), dan: -> lijn(void) geeft ambiguiteit bij de oproep lijn(), omdat de eerste functie niet kan worden overloaded met een functie met als argument void. -> lijn(char c) geeft ambiguiteit bij de oproep lijn( = ), omdat van de eerste functie en van de tweede functie het argument zonder default waarde, nl. char c, van hetzelfde type zijn en in dezelfde volgorde staan. Daardoor kan de eerste functie niet worden overloaden met de functie lijn(char c). -> lijn(int a) is OK. -> lijn(int a= 70) geeft abiguiteit bij de oproep lijn(), omdat het eerste argument van de eerste en van de tweede functie niet overeenkomen. -> lijn(char c, long lg= 50000) geeft ambiguiteit bij de oproep lijn( = ), omdat het tweede argument van de tweede functie een default waarde heeft. -> lijn(char c, int i) geeft ambiguiteit bij de oproep lijn( =, 70), omdat van beide functies de argumenten zonder default waarde van hetzelfde type zijn en in dezelfde volgorde staan. -> lijn (int i, char c) is OK, omdat van beide functies de argumenten niet in dezelfde volgorde staan. -> lijn(int i, int i) is Ok, omdat de compiler geen conversie doet en dus wel onderscheid kan maken. Wanneer de functies lijn(int, int) en lijn(long, long) worden opgeroepen met twee char s, dan zal de functie lijn(int, int) worden uitgevoerd omdat er een automatische conversie gebeurt naar het grotere type. Gezien het default argument geen deel uitmaakt van de functie, heeft dit volgende consequentie: de defintie void (*p1)(char, int) = &lijn // is OK doch de definitie void (*p1)(char) = &lijn // kan niet omdat het type niet overeen stemt. 1.12 New en delete 1.12.1 Dynamische geheugenallocatie In C++ wordt uitgebreid gebruik gemaakt van dynamische geheugenallocatie, noodzakelijk bij het alloceren van objecten die een levensduur hebben die langer is dan de procedure waarin ze aangemaakt zijn. Om het alloceren van objecten (het dynamisch toekennen van geheugen voor objecten) gemakkelijker te maken, is in T:\Modules\SYLLABUS\Programmeur X51\Programmeren in C++\020819 Programmeren in C++.doc