De presentatie wordt gedownload. Even geduld aub

De presentatie wordt gedownload. Even geduld aub

0 Inhoud Les 1 Les 3 Les 4 Les 6 Les 7 Les 9 Les 10 Les 12Les 15 Les 13Les 16Les 19 Les 18Les 21 Les 2Les 5Les 8Les 11Les 14Les 17Les 20.

Verwante presentaties


Presentatie over: "0 Inhoud Les 1 Les 3 Les 4 Les 6 Les 7 Les 9 Les 10 Les 12Les 15 Les 13Les 16Les 19 Les 18Les 21 Les 2Les 5Les 8Les 11Les 14Les 17Les 20."— Transcript van de presentatie:

1 0 Inhoud Les 1 Les 3 Les 4 Les 6 Les 7 Les 9 Les 10 Les 12Les 15 Les 13Les 16Les 19 Les 18Les 21 Les 2Les 5Les 8Les 11Les 14Les 17Les 20

2 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 1

3 2 Werkvormen OGOPRG  OGOPRG-co1 + OGOPRG-pr1 = 112 SBU.  21 uur theorie.  14 uur practicum.  77 uur zelfstudie = 9,5 uur/week zelfstudie!  Toetsing:  Schriftelijke toets OGOPRG-co1 in week 8 en 10 van dit kwartaal.  OGOPRG-pr1 practicumopgaven worden afgetekend op het practicum. Alle opgaven moeten voldoende zijn.

4 3 Inhoud  Objectgeoriënteerd Programmeren in C++.  responsibility driven design (ontwerpen uitgaande van verantwoordelijkheden).  information hiding (het afschermen van informatie door middel van het scheiden van interface en implementatie).  abstraction (het afschermen van complexiteit door middel van het scheiden van interface en implementatie).  inheritance (het mogelijk maken van een nieuwe vorm van hergebruik,... is een... in plaats van... heeft een...).  polymorphism (veelvormigheid mogelijk gemaakt door dynamic binding).  Objectgeoriënteerd Ontwerpen met UML.  klasse- en objectdiagrammen.  use-case-diagram.  sequence- en collaborationdiagrammen.  toestands- en activiteitendiagrammen.

5 4 Plaats in curriculum  Bouwt verder op GESPRG en MICPRG.  Voorbereiding voor ECV:  RTSYST Real-Time Systemen (verplicht)  ALGODS Algoritmen en Datastructuren (keuze)  Voorbereiding voor minor Embedded Systems

6 5 Leermiddelen  Blackboard OGOPRG.   Sheets, handouts.  Studiewijzer.  Practicumopdrachten.  Dictaat: Objectgeoriënteerd Programmeren in C++.  Boek:  Warmer & Kleppe, Praktisch UML, 5 de editie ISBN  Ontwikkelomgeving:  Microsoft Visual Studio Express 2012 for Windows Desktop.  Visual Paradigm for UML 10.0.

7 6 Een stapje verder...  Van gestructureerd naar objectgeoriënteerd.  C++ is een uitbreiding op C:  alles wat in C kan, kan ook in C++.  veel wat in C kan, kan in C++ beter (struct, array, c-string enz)....met programmeren en ontwerpen. GESPRG en MICPRG zijn het fundament voor OGOPRG. Zie dictaat blz. 1.

8 7  Gestructureerde programmeertalen:  ±1945 assembler, ±1957 FORTRAN, ±1960 Algol60, ±1972 C (1989 std ANSI C)  Software crisis:  Software niet op tijd geleverd.  Software duurder dan afgesproken.  Software niet foutloos.  Idee voor de oplossing:  Herbruikbare software componenten maken.  Deze componenten gebruiken bij maken van grote uitbreidbare en onderhoudbare software systemen.  Objectgeoriënteerde programmeertalen:  ±1967 Simula, ±1976 Smalltalk, ±1983 C++ (1998 std C++), ±1995 Java (Sun), ±2000 C# (Microsoft). lang Dat is een lang verhaal...

9 8 kort... maar ook een kort verhaal

10 9

11 10 Inleiding C++  Bjarne Stroustrup: “C++ is designed to:  be a better C.  support data abstraction.  support object-oriented programming.  support generic programming.” Huiswerk: Dictaat blz. 1 t/m 12 en practicumopdracht 1.

12 11 Practicumopdracht 1a #include using namespace std; int main() { cout << "Geef je adres: "; string mailAdres; cin >> mailAdres; string::size_type indexAt = if (indexAt != string::npos) { cout << "Gebruiker: " << mailAdres.substr(0, indexAt) << endl; cout << "Machine: " << mailAdres.substr(indexAt + 1) << endl; } else { cout << mailAdres << " is geen geldig adres!" << endl; } cout << "Druk op de return-toets." << endl; cin.get(); cin.get(); return 0; }

13 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 2

14 13 Vraag  Welke software hoeft nooit uitgebreid of veranderd te worden? Software die niemand gebruikt.

15 14 Nieuw!  Objectgeoriënteerd Programmeren is een nieuwe manier van denken... ... over hoe we code en informatie in een computerprogramma kunnen structureren.  Programmeer paradigma’s:  imperative (C, Pascal).  functional (LISP, Haskell).  logic (Prolog).  object oriented (C++, Java, C#).  generic (ADA, C++).

16 15 Objectgeoriënteerd Denken  De manier van probleem oplossen die gebruikt wordt bij de objectgeoriënteerde programmeertalen en ontwerpmethoden lijkt vaak op de manier van probleem oplossen die mensen in het dagelijks leven ook gebruiken.

17 16 Voorbeeld  Ik wil mijn oma een bosje bloemen sturen. • object • message + arguments • receiver's responsibility • method (information hiding)

18 17 Vraag  Wat is het verschil tussen een message en een functie?  Een message heeft een bepaalde receiver.  De method die bij de message hoort is afhankelijk van de receiver.  De receiver van een message kan ook tijdens run-time worden bepaald. Dynamic binding between the message (function name) and method (code).

19 18 Vraag  Waarom weet ik zoveel van mijn bloemiste? • class • instance (object) • hierarchy • inheritance (base and derived)

20 19 Method binding  Zoek in class van het receiver object.  Als daar geen method is zoek dan in de base class van de class van het receiver object.  Als daar geen method is zoek dan in de base class van de base class van de class van het receiver object.  Enzovoort. Een method uit de base class kan overriden worden door een method in een derived class.

21 20 Verband tussen classes  Aggregation = heeft een (of meer)  Inheritance = is een (speciaal soort) UML klassendiagram.

22 21 UML sequentiediagram

23 22 Steeds meer abstractie  Functions.  Avoid duplicating code.  Information hiding.  Modules.  Data and information hiding.  Abstract data types.  Instantiation.  Generic functions en generic ADT’s.  Templates.  Classes.  Messages.  Inheritance.  Polymorphism. Geschiedenis van programmeertechnieken.

24 23 Doel van object oriëntatie  Construeren van herbruikbare software componenten.  Gebruiken van deze componenten bij het construeren van grote aanpasbare en uitbreidbare systemen. Software IC Huiswerk: Bestudeer hoofdstuk 2 t/m 2.1 van het dictaat.

25 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 3

26 25 Herbruikbare component: Breuk  Waarom wil je programma’s maken die rekenen met breuken in plaats van met floating point getallen (double)?  Waarom wil je een component Breuk maken?  Hoe doe je dat in C?  Wat zijn de nadelen van de C oplossing?  Hoe kan het beter in C++?  Wat zijn de voordelen van de C++ oplossing?  Kan het nog mooier? Dictaat H2.2 t/m 2.28 (4 lessen).

27 26 Breuk in C  Gebruik struct voor dataopslag.  Gebruik functies voor bewerkingen. typedef struct { /* een breuk bestaat uit: */ int boven; /* een teller en */ int onder; /* een noemer */ } Breuk; Breuk normaliseer(Breuk b); Breuk som(Breuk b1, Breuk b2); Breuk som(Breuk b1, Breuk b2) { Breuk s; s.boven = b1.boven * b2.onder + b1.onder * b2.boven; s.onder = b1.onder * b2.onder; s = normaliseer(s); return s; } Prototypes of Functie declaraties Struct type declaratie Functie definitie

28 27 Gebruik  Nadelen Breuk in C  b1.onder = 0 is een “ramp die wacht om te gebeuren”.  Programmeur die het beter denkt te weten kan zelf breuken gaan optellen:  b3.teller = b1.teller + b2.teller; b3.noemer = b1.noemer + b2.noemer;  Verschillende programmeurs kunnen in verschillende delen van het programma de Breuk component uitbreidingen: B.v. functies: maal, times, en multiply. Breuk b1, b2, b3; b1.boven = 5; b1.onder = 12; b2.boven = 4; b2.onder = 9; b3 = som(b1, b2) Kan overal in het programma staan! OOPS!

29 28 Eigenschappen van C Breuk  Onderhoudbaarheid.  Fout in component is niet gemakkelijk te vinden.  Iedereen kan data van component “verzieken”.  Iedereen kan algoritme implementeren zonder implementatie van de component te gebruiken.  Als er “iets” niet goed gaat met component (b.v. vermenigvuldigen van breuken) moeten we het hele programma doorzoeken.  Aanpasbaarheid en uitbreidbaarheid.  Iedereen kan component aanpassen en uitbreiden.  Herbruikbaarheid.  Onduidelijk welke functies bij component horen en welke functies bij deze applicatie horen (en toevallig deze component gebruiken). Slecht! Te Goed!

30 29 Breuk in C++  Gebruik class voor dataopslag en bewerkingen. class Breuk { public: void leesin(); void drukaf() const; void plus(Breuk b); private: int boven; int onder; void normaliseer(); }; void Breuk::plus(Breuk b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); } Private data members Class declaratie Memberfunctie definitie Public memberfuncties = interface Private memberfunctie

31 30 Gebruik  Voordelen Breuk in C++  b1.onder = 0 geeft compilerfout.  Programmeur die het beter denkt te weten kan zelf geen breuken gaan optellen (zonder Breuk::plus te wijzigen).  Component Breuk kan slechts op 1 plaats in het programma uitgebreid worden. Breuk a, b; a.leesin(); b.leesin(); a.plus(b); a.drukaf();

32 31 Eigenschappen van C++ Breuk  Onderhoudbaarheid.  Fout in component is gemakkelijk te vinden.  Als er “iets” niet goed gaat met component hoef je alleen de implementatie van de component te doorzoeken. Fout moet in memberfuncties van de component zitten.  Je kunt niet (eenvoudig) om de interface van de class heenwerken. (Je kan zelf geen plus maken als je niet bij boven en onder kunt komen.)  Aanpasbaarheid en uitbreidbaarheid.  Component kan maar op 1 plaats uitgebreid worden.  Private delen kunnen aangepast worden zonder dat de interface veranderd. Dus zonder dat de code die de component gebruikt dit merkt! Zie practicum opgave 2c.  Herbruikbaarheid.  Duidelijk welke functies bij component horen. Goed! Redelijk. Goed! Huiswerk: Bestudeer paragraaf 2.2 van het dictaat.

33 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 4

34 33 Kenmerken van objecten  In de vorige lessen hebben we de volgende objecten leren kennen: Sonja en Corien (van de class Bloemiste ) en a en b (van de class Breuk ).  Kenmerken:  Geheugen (state). Elk object heeft zijn “eigen” geheugen.  Gedrag (behavior). Alle objecten van dezelfde class hebben hetzelfde gedrag.  Identiteit (identity). Elk object heeft een “eigen” identiteit (b.v. een naam).

35 34 Class Breuk (versie 1) class Breuk { public: Breuk(); Breuk(int t); Breuk(int t, int n); int teller() const; int noemer() const; void plus(Breuk b); void abs(); private: int boven; int onder; void normaliseer(); }; •Data members •Memberfuncties: •Constructors •Vraag-functies. •Doe-functies. int main() { Breuk a, b(-2), c(21, -9); //...

36 35 Class Breuk (versie 1) int main() { Breuk a, b(-2), c(21, -9); cout << a.teller() << "/" << a.noemer() << endl; cout << b.teller() << "/" << b.noemer() << endl; cout << c.teller() << "/" << c.noemer() << endl; c.abs(); cout << c.teller() << "/" << c.noemer() << endl; cin.get(); return 0; }

37 36 Implementatie constructors Breuk::Breuk(): boven(0), onder(1) { } Breuk::Breuk(int t): boven(t), onder(1) { } Breuk::Breuk(int t, int n): boven(t), onder(n) { normaliseer(); } Initialization list int main() { Breuk h("half"); return 0; } Werkt dit? Wat moet je doen om dit wel te laten werken?

38 37 Constructor  Compiler roept de constructor automatisch aan. { Breuk c(21, -9); //... } Reserveer geheugen op de stack voor c en roep constructor c.Breuk(21, -9) aan Roep destructor c.~Breuk() aan en geef geheugen van c weer vrij

39 38 Constructor en type conversie  Compiler roept de constructor automatisch aan als dat nodig is voor type conversie. { Breuk c(21, -9); //... c.plus(5); //... } Reserveer geheugen op de stack en roep constructor Breuk(5) aan Roep destructor aan en geef geheugen van Breuk(5) weer vrij c.plus(Breuk(5)); De C++ compiler denkt met je mee! Als je dat niet wilt moet je explicit voor de constructor zetten.

40 39 Class Breuk class Breuk { public: void leesin(); void drukaf() const; int teller() const; int noemer() const; void plus(Breuk b); void abs(); private: int boven; int onder; void normaliseer(); }; int main() { Breuk a, b; a.drukaf(); a.leesin(); b = a; b.drukaf(); Breuk c(a); c.drukaf(); return 0; } Werkt dit?

41 40 Gratis bij elke class!  constructor zonder argument (default constructor). Deze constructor roept de default constructor aan van alle data members.  copy constructor. Deze constructor roept de copy constructor aan van alle data members.  assignment operator ( operator= ). Deze assignment operator roept de assignment operator aan van alle data members.  destructor. Deze destructor roept de destructor aan van alle data members. Je kunt al deze functies ook zelf definiëren!

42 41 constconst const Breuk / const memberfuncties  Je kunt een constante Breuk definiëren. const Breuk kwart(1, 4); cout << kwart.teller() << '/' << kwart.noemer() << endl; // mag dit ? kwart.plus(5); // mag dit ? Hoe weet de compiler dat?

43 42 Class Breuk (versie 1) class Breuk { public: Breuk(); Breuk(int t); Breuk(int t, int n); int teller() const; int noemer() const; void plus(Breuk b); void abs(); private: int boven; int onder; void normaliseer(); }; •Vraag-functies: •Return type •Geen argumenten •const •Doe-functies: •Geen return type (void) •Meestal argumenten Breuk b(3, 4); const Breuk kwart(1, 4); cout << b.teller() << endl; b.plus(kwart); cout << kwart.teller() << endl; kwart.plus(b);

44 43 Huiswerk!  Bestudeer dictaat 2.3 t/m  Compileert dit programma bij gebruik van versie 1 van Breuk ?  Wat is de lengte en breedte van r1 en r2 ? class Rechthoek { public: //... (geen constructors) private: Breuk lengte; Breuk breedte; }; int main() { Rechthoek r1; //... Rechthoek r2(r1); //... }

45 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 5

46 45 Class Breuk  Kan het beter?  Stel hergebruik Breuk component is succes!  Helpfiles  FAQ Breuk a, b; a.leesin(); b.leesin(); a.plus(b); a.drukaf(); Breuk a, b; cin >> a >> b; a += b; cout << a; Gebruik Breuk is vergelijkbaar met int! Veel werk! Moeite waard?

47 46 Operator overloading a += b; a.operator+=(b); De C++ compiler denkt met je mee!

48 47 Breuk in C++ class Breuk { public: void leesin(); void drukaf() const; void operator+=(Breuk b); private: int boven; int onder; void normaliseer(); }; void Breuk::operator+=(Breuk b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); } Operator overloading is simpel! ?

49 48 Breuk is een succes!  Mag a += b += c met int?  Wat betekent het dan?  Oplossing?  b += c; a += b;  Kan dat niet beter?

50 class Breuk { public: void leesin(); void drukaf() const; Breuk operator+=(Breuk b); private: int boven; int onder; void normaliseer(); }; Breuk Breuk::operator+=(Breuk b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); return ?????; } class Breuk { public: void leesin(); void drukaf() const; Breuk operator+=(Breuk b); private: int boven; int onder; void normaliseer(); }; Breuk Breuk::operator+=(Breuk b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); return *this; } 49 Fix Breuk::operator+= Pas op! Deze code is niet correct. Zie volgende sheet.

51 50 Breuk is geen succes!  Oplossing?  reference

52 51 Reference  In C++ zijn er 3 “soorten” variabelen:  “Gewone” variabelen.  Pointers.  References. Een reference is een andere naam voor een variabele die al bestaat. int i; int& j = i; //initialisatie is verplicht! i = 3; cout << j << endl; // een reference is een "pseudoniem" Is dit goed voor de onderhoudbaarheid?

53 52 Gebruik reference  Je kunt een reference gebruiken als:  Globale variabele.  Lokale variabele.  Parameter.  Return type.

54 53 Call by value void swap(int p, int q) { int t = p; p = q; q = t; } //... int i = 3; int j = 4; swap(i, j); //... Deze code werkt niet goed! Weet je nog waarom? Oplossing?

55 54 Call by reference in C void swap(int* p, int* q) { int t = *p; *p = *q; *q = t; } //... int i = 3; int j = 4; swap(&i, &j); //... p wijst naar i q wijst naar j

56 55 Call by reference in C++ void swap(int& p, int& q) { int t = p; p = q; q = t; } //... int i = 3; int j = 4; swap(i, j); //... p is andere naam voor i q is andere naam voor j Onder de “motorkap” wordt een reference geïmplementeerd met een pointer.

57 56 Reference return  Je kunt een reference ook teruggeven vanuit een functie. int& max(int& a, int& b) { if (a > b) return a; else return b; } int main() { int x = 2, y = 7, z; max(x, y) = 0; z = max(x, y); //... } Een functie die een reference teruggeeft kan ook links van een = teken gebruikt worden (is een lvalue).

58 57 Fix Breuk::operator+= class Breuk { public: void leesin(); void drukaf() const; Breuk& operator+=(Breuk b); private: int boven; int onder; void normaliseer(); }; Breuk& Breuk::operator+=(Breuk b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); return *this; } Met behulp van een reference kunnen we ook onnodige kopietjes voorkomen.

59 58 Fix Breuk::operator+= class Breuk { public: void leesin(); void drukaf() const; Breuk& operator+=(const Breuk& b); private: int boven; int onder; void normaliseer(); }; Breuk& Breuk::operator+=(const Breuk& b) { boven = boven * b.onder + onder * b.boven; onder *= b.onder; normaliseer(); return *this; } Waarom const?

60 59 Huiswerk!  Bestudeer dictaat 2.11 t/m  Een reference lijkt op een pointer. Wat zijn de verschillen?  Noem 3 situaties waar een copy constructor nodig is.  Waarom zijn de parameters van max (zie boven) geen int of const int& ?  Zorg dat dit programmadeel werkt: int main() { Breuk a, b, c; //... c = a + b; //... }

61 OGOPRG Les 6 Objectgeoriënteerd Programmeren in C++

62 61 Operator+ overloading { Breuk a, b, c; c = a + b; } c.operator=(a.operator+(b)); Gratis! Zelf maken  Wat moet operator+ eigenlijk doen?  Wat moet het parametertype zijn?  Breuk Goed  const Breuk& Beter! Voorkomt onnodig kopietje.  Wat moet het returntype zijn?  Breuk Goed  Breuk& Fout! Je hebt geen variabele die al bestaat.  const Breuk Beter! Geeft een fout bij: a + b = c;

63 62 Breuk::operator+ class Breuk { public: //... Breuk& operator+=(const Breuk& rechts); const Breuk operator+(const Breuk& rechts) const; private: int boven; int onder; void normaliseer(); }; const Breuk Breuk::operator+(const Breuk& rechts) const { Breuk hulpje(*this); hulpje += rechts; return hulpje; } Waarom const?

64 63 Breuk::operator+  De volgende implementaties zijn niet juist! const Breuk Breuk::operator+(const Breuk& rechts) { Breuk hulpje(*this); hulpje += rechts; return hulpje; } const Breuk& Breuk::operator+(const Breuk& rechts) const { Breuk hulpje(*this); hulpje += rechts; return hulpje; } const Breuk& Breuk::operator+(const Breuk& rechts) const { *this += rechts; return *this; } // Hint: const Breuk kwart(1, 4); Breuk b(2, 3), c; c = kwart + b; const vergeten! Return andere naam voor een “dode” variabele! Receiver mag niet veranderen!

65 64 Breuk::operator+ probleem! { Breuk a, b; b = a + 5; b = 5 + a; } b.operator=(a.operator+(5)); Breuk(5) b.operator=(5.operator+(a)); Microsoft error: binary ' + ' : no global operator found which takes type ' Breuk '. GNU gcc error: No match for ' operator+ ' in ' 5 + a '. Oplossing?

66 65 Globale operator+ overloading  Je kunt de globale operator+ overloaden. class Breuk { public: //... Breuk& operator+=(const Breuk& rechts); const Breuk operator+(const Breuk& rechts) const; private: //... }; const Breuk operator+(int links, const Breuk& rechts); const Breuk operator+(int links, const Breuk& rechts) { Breuk hulpje(links); hulpje += rechts; return hulpje; }

67 66 Fix: Breuk::operator+ { Breuk a, b; b = a + 5; b = 5 + a; } b.operator=(a.operator+(5)); Breuk(5) b.operator=(operator+(5, a)); Kan dit niet eenvoudiger?

68 67 Globale operator+ overloading  Alternatief: class Breuk { public: //... Breuk& operator+=(const Breuk& rechts); private: //... }; const Breuk operator+(const Breuk& links, const Breuk& rechts); const Breuk operator+(const Breuk& links, const Breuk& rechts) { Breuk hulpje(links); hulpje += rechts; return hulpje; }

69 68 Fix: Breuk::operator+ { Breuk a, b; b = a + 5; b = 5 + a; } b.operator=(operator+(a, 5)); Breuk(5) b.operator=(operator+(5, a)); Breuk(5)

70 69 Operator== overloading  Wat moet operator== eigenlijk doen?  Waarom heb ik de globale operator== gebruikt en niet Breuk::operator== ?  Wat moeten de parametertypes zijn?  Breuk Goed  const Breuk& Beter! Voorkomt onnodig kopietje.  Wat moet het returntype zijn?  bool Goed { Breuk a, b; if (a == b) /*... */; } if (operator==(a, b))

71 70 Operator== overloading  Je kunt de globale operator== overloaden. class Breuk { public: //... int teller() const; int noemer() const; private: //... }; bool operator==(const Breuk& l, const Breuk& r); bool operator==(const Breuk& l, const Breuk& r) { return l.teller() == r.teller() && l.noemer() == r.noemer(); }

72 71 Breuk::operator==  Waarom is de volgende implementatie niet juist! Error: boven en onder zijn private! class Breuk { public: //... private: int boven; int onder; //... }; bool operator==(const Breuk& l, const Breuk& r); bool operator==(const Breuk& l, const Breuk& r) { return l.boven == r.boven && l.onder == r.onder; } Wat te doen als er geen teller() en noemer() memberfuncties zijn ?

73 72 Breuk::operator==  Friend! class Breuk { public: //... private: int boven; int onder; //... friend bool operator==(const Breuk& l, const Breuk& r); }; bool operator==(const Breuk& l, const Breuk& r) { return l.boven == r.boven && l.onder == r.onder; }

74 73 Friend  Vriendschap in C++ gaat wel erg ver...  Geldt bij het gebruik van friend nog steeds het principe van information hiding? A friend is someone who may touch your private parts.

75 74 Huiswerk!  Bestudeer dictaat 2.21 t/m Let op! 2.24 en 2.25 zijn niet behandeld (mag je overslaan).  Maak een operator*= voor Breuk.  Maak een operator* voor Breuk.  Maak een operator!= voor Breuk.  Maak een operator< voor Breuk.  Maak een operator<= voor Breuk.  Maak een operator> voor Breuk.  Maak een operator>= voor Breuk. Denk aan OO “afschuiven”!

76 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 7

77 76 Operator<< overloading  We willen breuken op dezelfde manier afdrukken als integers. { Breuk b(12, -9); cout << "b = " << b << endl; //... } cout.operator<<("b = ").operator<<(b). operator<<(endl); Bestaat al!Zelf makenBestaat al! Object van de class ostream ostream aanpassen?

78 77 Operator<< overloading  We willen breuken op dezelfde manier afdrukken als integers. { Breuk b(12, -9); cout << "b = " << b << endl; //... } operator<<(cout.operator<<("b = "), b).operator<<(endl); Bestaat al!Zelf makenBestaat al! Object van de class ostream Globale operator<< overloaden

79 78 Operator<< overloading  Wat moet het eerste parametertype zijn?  ostream De uitvoer moet niet naar een kopietje van het beeldschermgeheugen.  ostream& Goed  Wat moet het tweede parametertype zijn?  Breuk Goed  const Breuk& Beter! Voorkomt onnodig kopietje.  Wat moet het returntype zijn?  ostream De endl moet niet naar een kopietje van het beeldschermgeheugen.  ostream& Goed { Breuk a; cout << a << endl; } operator<<(cout, a). operator<<(endl);

80 79 Operator<< class Breuk { public: //... private: int boven; int onder; //... friend ostream& operator<<(ostream& left, const Breuk& right); }; ostream& operator<<(ostream& left, const Breuk& right) { left << right.boven << '/' << right.onder; return left; }

81 80 Gemak van overerving  Er zijn verschillende classes afgeleid van ostream.  ostringstream Om te schrijven naar een string variabele.  ofstream Om te schrijven naar een file.  De overloaded operator<< kan ook met objecten van deze afgeleide classes worden gebruikt. ostream ostringstreamofstream

82 81 Gemak van overerving class Breuk { //... friend ostream& operator<<(ostream& left, const Breuk& right); }; //... int main() { Breuk b(12,-9); ofstream out("uitvoer.txt"); if (out) out << "b = " << b << endl; else cerr << "File uitvoer.txt kan niet geopend worden!" << endl; cin.get(); return 0; } Gaat goed! Want ofstream “is een” ostream.

83 82 Operator>> overloading  We willen breuken op dezelfde manier inlezen als integers. { int i, j; Breuk b; cin >> i >> b >> j; //... } cin.operator>>(i).operator>>(b). operator>>(j); Bestaat al!Zelf maken Object van de class istream istream aanpassen? Bestaat al!

84 83 Operator>> overloading  We willen breuken op dezelfde manier inlezen als integers. { int i, j; Breuk b; cin >> i >> b >> j; //... } operator>>(cin.operator>>(i), b). operator>>(j); Bestaat al!Zelf makenBestaat al! Object van de class istream Globale operator>> overloaden

85 84 Operator>> overloading  Wat moet het eerste parametertype zijn?  istream De invoer moet niet worden gelezen uit een kopietje van het toetsenbordbuffer.  istream& Goed  Wat moet het tweede parametertype zijn?  Breuk De invoer moet niet naar een kopietje van a.  Breuk& Goed  Wat moet het returntype zijn?  istreami moet niet worden gelezen uit een kopietje van het toetsenbordbuffer.  istream& Goed { Breuk a; int i; cin >> a >> i; } operator>>(cin, a). operator>>(i);

86 85 Operator>> istream& operator>>(istream& left, Breuk& right) { int teller; if (isdigit(left.peek()) && left >> teller) if (left.peek() == '/') { left.get(); int noemer; if (isdigit(left.peek()) && left >> noemer) right = Breuk(teller, noemer); else right = Breuk(teller); } else right = Breuk(teller); else right = Breuk(); return left; } Deze operator>> hoeft geen friend te zijn van de class Breuk

87 86 Huiswerk!  Bestudeer dictaat 2.28.

88 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 8

89 88 Seperate compilation #ifndef _Memcell_ #define _Memcell_ class MemoryCell { public: int Read() const; void Write(int x); private: int StoredValue; }; #endif #include "Memcell.h" int MemoryCell::Read() const { return StoredValue; } void MemoryCell::Write(int x) { StoredValue = x; } #include using namespace std; #include "Memcell.h" int main() { MemoryCell M; M.Write(5); cout << "Cell contents are " << M.Read() << endl; Memcell.h Memcell.cpp Memappl.cpp

90 89 Seperate compilation Memcell.h class MemoryCell { //... }; Memcell.cpp #include "Memcell.h" //... int MemoryCell::Read() { Memappl.cpp #include "Memcell.h" //... MemoryCell M; Memcell.obj Memappl.obj Memcell.exe compiler linker pre-compiler

91 90 Project  Microsoft Visual C

92 91 Hergebruik  Wat te doen als we twee variabelen van het type double willen verwisselen?  Wat te doen als we twee objecten van de class Breuk willen verwisselen? void swap(int& p, int& q) { int t = p; p = q; q = t; } //... int i = 3; int j = 4; swap(i, j); //... Copy – Paste is slecht voor de onderhoudbaarheid!

93 92 Generieke functie  Gebruik een template functie. template void swap(T& p, T& q) { T t = p; p = q; q = t; } //... int i = 3; int j = 4; swap(i, j); //... Breuk b(1, 2); Breuk c(3, 4); swap(b, c); Een template is een “mal” waarmee verschillende functies “gemaakt” kunnen worden void swap(int& p, int& q) { int t = p; p = q; q = t; } void swap(Breuk& p, Breuk& q) { Breuk t = p; p = q; q = t; }

94 93 Class Dozijn  In de class Dozijn kun je 12 integers opslaan. class Dozijn { public: void zetIn(int index, int waarde); int leesUit(int index) const; private: int data[12]; }; //... Dozijn d; d.zetIn(3, 13); //... cout << "De plaats nummer 3 in d bevat de waarde: " << d.leesUit(3) << endl;

95 94 Class Dozijn void Dozijn::zetIn(int index, int waarde) { if (index >= 0 && index < 12) data[index] = waarde; } int Dozijn::leesUit(int index) const { if (index >= 0 && index < 12) return data[index]; return 0; /* ik weet niets beters */ } ostream& operator<<(ostream& o, const Dozijn& d) { o << d.leesUit(0); for (int i = 1; i < 12; ++i) o << ", " << d.leesUit(i); return o; }

96 95 Copy – Paste is slecht voor de onderhoudbaarheid! Class Dozijn  Wat te doen als we 12 variabelen van het type double willen opslaan?  Wat te doen als we 12 objecten van de class Breuk willen opslaan? int main() { Dozijn d1; for (int j = 0; j < 12; ++j) d1.zetIn(j, j * j); // vul d1 met kwadraten cout << "d1 = " << d1 << endl; cin.get(); return 0; } d1 = 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121

97 96 Generieke class  Gebruik een template class. template class Dozijn { public: void zetIn(int index, const T& waarde); const T& leesUit(int index) const; private: T data[12]; }; //... Dozijn di; Een template is een “mal” waarmee verschillende classes “gemaakt” kunnen worden class Dozijn { public: void zetIn(int index, const int& waarde); const int& leesUit(int index) const; private: int data[12]; };

98 97 Generieke class Dozijn template void Dozijn ::zetIn(int index, const T& waarde) { if (index >= 0 && index < 12) data[index] = waarde; } template const T& Dozijn ::leesUit(int index) const { if (index < 0) index = 0; if (index > 11) index = 11; return data[index]; } template ostream& operator & d) { o << d.leesUit(0); for (int i = 1; i < 12; ++i) o << ", " << d.leesUit(i); return o; }

99 Generieke class Dozijn int main() { Dozijn d1; for (int j = 0; j < 12; ++j) d1.zetIn(j, j * j); // vul d1 met kwadraten cout << "d1 = " << d1 << endl; Dozijn d2; d2.zetIn(0, "Drenthe"); d2.zetIn(1, "Flevoland"); //... d2.zetIn(10, "Zeeland"); d2.zetIn(11, "Zuid-Holland"); cout << "d2 = " << d2 << endl; cin.get(); return 0; } 98 Wat doen we als we meer/minder dan 12 elementen willen opslaan? d1 = 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121 d2 = Drenthe, Flevoland, Friesland, Gelderland, Groningen, Limburg, Noord-Brabant, Noord-Holland, Overijssel, Utrecht, Zeeland, Zuid-Holland

100 99 Generieke class  Gebruik een tweede template parameter. template class Rij { public: void zetIn(int index, const T& waarde); const T& leesUit(int index) const; int aantalPlaatsen() const; private: T data[N]; }; //... Rij alfabet; Een template is een “mal” waarmee verschillende classes “gemaakt” kunnen worden class Rij { public: void zetIn(int index, const char& waarde); const char& leesUit(int index) const; int aantalPlaatsen() const; private: char data[26]; };

101 100 Generieke class Rij template void Rij ::zetIn(int index, const T& waarde) { if (index >= 0 && index < N) data[index] = waarde; } template const T& Rij ::leesUit(int index) const { if (index < 0) index = 0; if (index > N - 1) index = N - 1; return data[index]; } template int Rij ::aantalPlaatsen() const { return N; } template ostream& operator & r) { o << r.leesUit(0); for (int i = 1; i < N; ++i) o << ", " << r.leesUit(i); return o; }

102 Generieke class Rij int main() { Rij kwad; for (int i = 0; i < kwad.aantalPlaatsen(); ++i) kwad.zetIn(i, i * i); cout << "kwad = " << kwad << endl; Rij alfabet; for (int i = 0; i < alfabet.aantalPlaatsen(); ++i) alfabet.zetIn(i, 'A' + i); cout << "alfabet = " << alfabet << endl; cout << "de derde letter van alfabet is " << alfabet.leesuit(2) << endl; cout << "de honderste letter van alfabet is " << alfabet.leesuit(99) << endl; cin.get(); return 0; } 101 kwad = 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 alfabet = A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z de derde letter van alfabet is C de honderste letter van alfabet is Z

103 102 Template class std::array C++11  std::array in C++ vervangt de C array.  Het aantal elementen N ligt vast na het compileren.  Elementen kunnen worden opgevraagd met operator[].  Je kunt een std::array “gewoon” vergelijken, toekennen en kopiëren.  Je kunt een std::array element voor element doorlopen met een range-based for.  std::array heeft memberfuncties:  size() geeft het aantal elementen (type: std::array ::size_type ).  at(n) geeft reference naar element n. Geeft een fout (exception) als element n niet bestaat.

104 Template class std::array C #include using namespace std; int main() { // definieer array van 15 integers array a; // vul met kwadraten for (array ::size_type i = 0; i < a.size(); ++i) { a[i] = i * i; } // druk af for (array ::size_type i = 0; i < a.size(); ++i) { cout << a[i] << " "; } cout << endl; //...

105 Template class std::array C #include using namespace std; int main() { // definieer array van 15 integers array a; // vul met kwadraten for (decltype(a.size()) i = 0; i < a.size(); ++i) { a[i] = i * i; } // druk af for (decltype(a.size()) i = 0; i < a.size(); ++i) { cout << a[i] << " "; } cout << endl; //... decltype geeft het type van een expressie Waarom werkt auto hier niet?

106 Template class std::array C #include using namespace std; int main() { // definieer array van 15 integers array a; // vul met kwadraten int i = 0; for (int& e: a) { e = i * i; ++i; } // druk af for (int e: a) { cout << e << " "; } cout << endl; //...

107 106 Template class std::vector  std::vector in C++ is een dynamische array.  De std::vector kan groeien en krimpen.  Elementen kunnen worden opgevraagd met operator[].  Je kunt een std::vector “gewoon” vergelijken, toekennen en kopiëren.  Je kunt een std::vector element voor element doorlopen met een range-based for.  std::vector heeft memberfuncties:  size() geeft het aantal elementen (type: std::vector ::size_type ).  at(n) geeft reference naar element n. Geeft een fout (exception) als element n niet bestaat.  push_back(e) voeg element e aan de vector toe.

108 107 Template class std::vector #include using namespace std; int main() { // definieer vector van integers vector v; // vul met kwadraten for (int i = 0; i < 15; ++i) { v.push_back(i * i); } // druk af for (vector ::size_type i = 0; i < v.size(); ++i) { cout << v[i] << " "; } cout << endl; //...

109 108 Template class std::vector C++11 #include using namespace std; int main() { // definieer vector van integers vector v; // vul met kwadraten for (int i = 0; i < 15; ++i) { v.push_back(i * i); } // druk af for (decltype(v.size()) i = 0; i < v.size(); ++i) { cout << v[i] << " "; } cout << endl; //...

110 109 Template class std::vector C++11 #include using namespace std; int main() { // definieer vector van integers vector v; // vul met kwadraten for (int i = 0; i < 15; ++i) { v.push_back(i * i); } // druk af for (int e: v) { cout << e << " "; } cout << endl; //...

111 110 Huiswerk!  Bestudeer dictaat  Bestudeer dictaat (heel) hoofdstuk 3.

112 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 9

113 112 Hergebruik van classes  Aggregatie (Aggregation) ... heeft een (of meer)...  Overerving (Inheritance) ... is een (speciaal soort)...

114 113 Aggregatie  Aggregatie (Aggregation) ... heeft een (of meer)... Een Rechthoek heeft een lengte en een breedte van het type Breuk. class Rechthoek { public: //... private: Breuk lengte; Breuk breedte; };

115 114 Overerving  Overerving (Inheritance) ... is een (speciaal soort)... Een Bloemiste is een (speciaal soort) Winkelier. class Winkelier { //... }; class Bloemiste: public Winkelier { //... };

116 115 ADT aanpak enum Soort {sintBernard, tekkel}; class Hond { private: Soort s; //... public: Krant haalKrant(); void blaf(); //... }; Krant Hond::haalKrant() { //... blaf(); return krant; } void Hond::blaf() { switch (s) { case sintBernard: cout << "WOEF WOEF"; break; case tekkel: cout << "kef kef"; break; } Niet goed uitbreidbaar!

117 116 OO aanpak  Een Tekkel is een Hond.  Een SintBernard is een Hond. class Hond { private: //... public: Krant haalKrant(); virtual void blaf(); //... }; Krant Hond::haalKrant() { //... blaf(); return krant; } void Hond::blaf() { cout << "blaf blaf"; } Message kan overridden worden.

118 117 OO aanpak class SintBernard: public Hond { private: Whisky vat; public: virtual void blaf(); }; void SintBernard::blaf() { cout << "WOEF WOEF"; } class Tekkel: public Hond { public: virtual void blaf(); }; void Tekkel::blaf() { cout << "kef kef"; }

119 118 Polymorfisme void doeJeWerk(Hond& h) { Krant k = h.haalKrant(); //... } int main() { SintBernard Boris; Tekkel Harry; if (!weekend) doeJeWerk(Harry); else if (zaterdag) doeJeWerk(Boris); cin.get(); return 0; } Harry is van de class Tekkel maar een Tekkel is een Hond. Boris is van de class SintBernard maar een SintBernard is een Hond. h is een polymorfe parameter. doeJeWerk is een polymorfe functie.

120 119 Uitbreidbaarheid  Door de OO aanpak kan heel eenvoudig een nieuwe soort hond worden toegevoegd.  Voeg zelf de classes DuitseHerder en MechelseHerder toe.  Welke code moet nu gewijzigd worden?  Welke code moet nu opnieuw gecompileerd worden?

121 120 Huiswerk!  Bestudeer dictaat hoofdstuk 4 t/m 4.2.  Voeg zelf zelf de classes DuitseHerder en MechelseHerder toe. Gegeven is dat beide rassen Herdershonden zijn die een schapenkudde kunnen drijven en hoeden. Elk ras heeft een eigen blaf.  Beantwoord de vragen op de vorige sheet.

122 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 10

123 122 Uitwerking Huiswerk  Voeg DuitseHerder en MechelseHerder toe.  Welke code moet gewijzigd worden?  Welke code moet gecompileerd worden?

124 123 Tiroler Herder © Toon van Driel

125 124 Tiroler Herder © Toon van Driel

126 125 Inline memberfuncties  Definitie van de memberfuncties staat in de class declaratie.  Nadeel:  Component kan niet zonder source geleverd worden.  Voordeel:  Minder typen. class Hond { public: virtual void blaf() { cout << "blaf blaf"; } }; class SintBernard: public Hond { public: virtual void blaf() { cout << "WOEF"; } private: Whisky vat; };

127 126 Boodschap sturen via pointer class Hond { public: virtual void blaf() { cout << "blaf blaf" << endl; } }; int main() { Hond fikkie; fikkie.blaf(); Hond* phond(&fikkie); *phond.blaf(); (*phond).blaf(); phond->blaf(); Error: left of '.blaf ' must have class/struct Ok Handige afkorting

128 int main() { SintBernard boris; Hond& rhond = boris; rhond.blaf(); Hond* phond = &boris; phond->blaf(); Hond hond = boris; hond.blaf(); 127 Slicing problem  polymorfisme werkt alleen bij * en &. class Hond { public: virtual void blaf() { cout << "blaf" << endl; } }; class SintBernard: public Hond { public: virtual void blaf() { cout << "WOEF" <

129 128 Abstract Base Class  Er kunnen geen objecten (variabelen) van een ABC gedefinieerd worden.  Een class die overerft van Hond en blaf() override is geen ABC meer.  Een class die overerft van Hond en blaf() niet override is een ABC. class Hond { private: //... public: Krant haalKrant(); virtual void blaf() = 0; //... }; Krant Hond::haalKrant() { //... blaf(); return krant; } Puur virtueel Oplossing voor het Slicing Problem

130 Slicing problem  polymorfisme werkt alleen bij * en &. int main() { SintBernard boris; Hond& rhond = boris; rhond.blaf(); Hond* phond = &boris; phond->blaf(); Hond hond = boris; class Hond { public: virtual void blaf() = 0; }; class SintBernard: public Hond { public: virtual void blaf() { cout << "WOEF" << endl; } private: Whisky vat; }; Error: ' Hond ' : cannot instantiate abstract class due to following members: ' void Hond::blaf(void) ' : is abstract Hond is een ABC 129

131 130 Slicing Problem  Maak alle base classes abstract.  Compiler voorkomt slicing!  Kan niet altijd:  Hergebruik class van een andere programmeur (evt. zonder source code).  Je moet nu zelf slicing voorkomen!

132 131 Huiswerk!  Bestudeer dictaat paragraaf 4.3 t/m 4.5 en  4.3: Memberfunctie overriding. Vanuit de in de derived class overridden memberfunctie kun je de originele functie in de base class aanroepen.  4.4: Abstract base class.  4.5: Constructors bij inheritance. Vanuit de constructor van de derived wordt automatisch de constructor van de base class aangeroepen. Je kunt ook zelf vanuit de constructor van de derived class een constructor in de base class aanroepen.  4.11: Slicing problem. Nodig bij practicumopdracht 3a

133 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 11

134 133 Overloading van memberfuncties class Class { public: void f() const { cout << "Ik ben f()" << endl; } void f(int i) const { // overload f() cout << "Ik ben f(int)" << endl; } }; int main() { Class object; object.f(); object.f(3); //... Uitvoer: Ik ben f() Ik ben f(int)

135 class Base { public: void f() const { cout << "Ik ben f()" << endl; } }; class Derived: public Base { public: void f(int i) const { // Verberg f() cout << "Ik ben f(int)" << endl; } }; Overloading en overerving Uitvoer: Ik ben f() Ik ben f(int) Ik ben f() int main() { Base b; Derived d; b.f(); d.f(3); d.f(); d.Base::f(); } Conclusie: Overloading en overerving gaan niet goed samen! Error: ' Derived::f ' : function does not take 0 arguments Hiding-rule 134

136 135 Reden voor de hiding-rule // Code van Bas class Base { public: // geen f(...) }; // Code van Dewi class Derived: public Base { public: void f(double d) const { cout << "Ik ben f(double)" << endl; } }; int main() { Derived d; d.f(3); //... Uitvoer: Ik ben f(double)

137 136 Reden voor de hiding-rule // Aangepaste code van Bas class Base { public: //... void f(int i) const { cout << "Ik ben f(int)" << endl; } }; // Code van Dewi niet gewijzigd int main() { Derived d; d.f(3); // Base::f(int) is hidden. Gelukkig maar! //... Uitvoer: Ik ben f(double) Conclusie: De hiding-rule verhoogt de onderhoudbaarheid!

138 Explicit overriding C++11  Sinds C++11 kun je expliciet aangeven dat je een memberfunctie wilt overridden. Dit voorkomt dat je een memberfunctie “per ongeluk” overload.  Dit doe je door het woord override achter de memberfunctie te plaatsen.  De compiler geeft nu een foutmelding als er geen overriding wordt gebruikt. 137

139 class Base { public: void f(int i) const { cout << "Base::f(int) called." << endl; } virtual void g(int i) const { cout << "Base::g(int) called." << endl; } }; class Derived: public Base { public: void f(int i) const override { cout << "Derived::f(int) called." << endl; } virtual void g(int i) override { cout << "Derived::g(int) called." << endl; } }; 138 Explicit overriding C++11 Error: ' Derived::f ' : method with override specifier ' override ' did not override any base class methods Error: ' Derived::g ' : method with override specifier ' override ' did not override any base class methods OOPS: virtual vergeten! OOPS: const vergeten!

140 Final overriding C++11 Je hebt blaf() in Herdershond overridden maar je wilt niet dat blaf() in classes die afgeleid zijn van Herdershond opnieuw overridden wordt. 139

141 Final overriding C class Herdershond: public Hond { public: virtual void blaf() final; //... }; class DuitseHerder: public Herdershond { public: virtual void blaf(); //... }; Error: ' Herdershond::blaf() ': declared as 'final' cannot be overridden by ' DuitseHerder::blaf '

142 141  private:  alleen bereikbaar in member functies van de class zelf  protected:  alleen bereikbaar in member functies van de class en in member functies van "nakomelingen" van de class  public:  altijd bereikbaar via object Afscherming Zie dictaat paragraaf 4.6.

143 142 Proeftentamen  Tentamenopgaven over de tot nu toe behandelde stof.

144 143 Huiswerk!  Bestudeer dictaat paragraaf 4.6 t/m 4.10, 4.12 en  4.6: protected members.  4.7: Voorbeeld: ADC kaarten.  4.8: Overloading en overriding van memberfuncties.  4.9: Expliciet overridden van memberfuncties.  4.10: Final overridden van memberfuncties.  4.12 Voorbeeld: Opslaan van polymorfe objecten in een vector.  4.13 Voorbeeld: Impedantie calculator. Nodig bij practicumopdracht 3c

145 144 Huiswerk!  Maak het proeftentamen.

146 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 12

147 146 Huiswerk!  Bestudeer boek: Warmer & Kleppe, Praktisch UML, 5 de editie.  H1 en H2  H4 t/m 4.3

148 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 13

149 148 Software Engineering Fases  Wat wil de klant?  Analyse (find the requirements).  Hoe kun je het maken?  Design (structured or OO).  Waarmee kun je het maken?  Implement (write the code).  Werkt het?  Test (verify and validate). Verification: Have we built the system right? Does the system satisfy its specification? Validation: have we built the right system? Does the specification satisfy the customer's expectation?

150 149 Software Engineering  Waterval methode  Traditionele methode.  Geschikt voor projecten met weinig risico.  Past goed bij gestructureerde aanpak.  Spiraal methode (Evolutionaire methode.)  Moderne methode.  Geschikt voor projecten met veel risico (onzekerheid).  Past goed bij OO aanpak.

151 150 Waterval = sequentieel Analyse Design Implement Test

152 151 Tijdsdruk... Versnellen door in elkaar schuiven van waterval model geeft problemen!

153 152 Spiraal = cyclisch Analyse DesignImplement Test Typische duur van één cyclus: 3 weken!

154 153 Modelleren Werkelijkheid model

155 154 Wat modelleren we?  Analyse  Maak een model van de te automatiseren werkelijkheid of van het op te lossen probleem.  Domeinkennis  structuur.  Functionele eisen  gedrag.  Ontwerp  Maak een model van de oplossing.  Implementatie  Maak een model van het programma. Bij OOA+OOD+OOP werken we steeds aan hetzelfde model (seamless development)

156 155 Unified Modeling Language  UML inleiding.  Hoofdstuk 1 en 2.  UML Klasse- en objectdiagram (1).  Paragraaf 4.1 t/m 4.3, 4.4.2, 4.4.8, en  UML Use-case-diagram.  Paragraaf 8.1 t/m 8.6.  UML Sequentie- en communicatiediagram.  Paragraaf 10.1 t/m  UML Toestands- en Activiteitsdiagram.  Paragraaf 12.1 t/m 12.3 en H15.1 t/m  UML Klassediagram (2)  Paragraaf 4.4.4, en

157 156 Visual Paradigm for UML  Tekenen van UML diagrammen.  Omzetten UML naar C++ (of Java, C#, Python enz).  Omzetten C++ (of Java, C#, Python) naar UML.  Beschikbaar in lokaal D1.052 (en ook thuis).

158 Visual Paradigm for UML SE 157

159 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 14

160 159 Klassediagram  Attributes = data members  Operations = member functions = messages In Visual Paradigm for UML kunnen attributes en operations “verborgen” worden.

161 160 Objectdiagram  Object is een instantie van een Class  Attributes = data members In Visual Paradigm for UML kunnen attributes met waarden “verborgen” worden.

162 161 Fases AnalysisDesign Tijdens het ontwikkelen van het model voeg je steeds meer details toe. Deze details kun je ook weer verbergen, zie: Project Options.

163 Code generatie  Twee methoden  Instant generator is the process of producing source code from class model.  Round-trip engineering is the ability to generate model from source code and generate source code from model, and keep them synchronized. 162

164 163 Implementation = Code generatie #ifndef __Rekening_h__ #define __Rekening_h__ class Rekening { public: bool open(); void stort(double bedrag); bool neemOp(double bedrag); private: double saldo; }; #endif #include "Rekening.h" bool Rekening::open() { } void Rekening::stort(double bedrag) { } bool Rekening::neemOp(double bedrag) { } Rekening.h Rekening.cpp Code moet nog worden ingevuld!

165 164 Implementation = Code generatie

166 165 Associatie Labels: Altijd invullen! Multipliciteit: eventueel invullen. Rol: eventueel invullen. Leesrichting: gebruiken om “onnatuurlijke” leesrichting aan te geven.

167 166 Overerving (... is een... ) Directeur.h #ifndef __Directeur_h__ #define __Directeur_h__ #include "Persoon.h" class Directeur: public Persoon { }; #endif

168 167 Aggregatie (... heeft een...)  Fiets heeft:  2 Wielen  1 Frame

169 168 Associatie  Overerving  Aggregatie  Compositie Een compositie is een speciaal soort aggregatie.  Aggregatie  “heeft een” relatie.  vaag gedefinieerd  Compositie  “bevat een” relatie.  deel behoort maar bij 1 geheel  levensduur deel <= levensduur geheel Beginnende UML modelleerders gebruiken vaak ten onrechte compositie!

170 169 Compositie (... bevat een...)  Welke aggregaties zijn composities?  Mens --- Nier  Mens --- Hersenen  PC --- Hard Disk  PC --- CPU  CPU --- Transistor  Radio --- Transistor Let op! Het goede antwoord is afhankelijk van de applicatie.

171 170 Compositie (... bevat een...) #ifndef __Fiets_h__ #define __Fiets_h__ #include "Frame.h" class Fiets { public: Frame Unnamed_Frame_; }; #endif

172 171 Compositie (... bevat een...)

173 172 Compositie (... bevat een...) #ifndef __Fiets_h__ #define __Fiets_h__ #include "Frame.h" class Fiets { private: Frame hetFrame; }; #endif

174 173 Compositie (... bevat een...) #ifndef __Frame_h__ #define __Frame_h__ #include "Fiets.h" class Frame { public: Fiets* Unnamed_Fiets_; }; #endif

175 174 Compositie (... bevat een...)

176 175 Compositie (... bevat een...) #ifndef __Frame_h__ #define __Frame_h__ class Frame { }; #endif #ifndef __Fiets_h__ #define __Fiets_h__ #include "Frame.h" class Fiets { private: Frame hetFrame; }; #endif

177 176 Commentaar

178 177 Huiswerk!  Bestudeer boek: Warmer & Kleppe, Praktisch UML, 5 de editie.  H1 en H2  H4 t/m 4.3, en  Vragen bij H2 en H4 (zie BB)  Bedenk hoe je een aggregatie (geen compositie) kunt implementeren. Zie dictaat:  paragraaf 4.12.

179 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 15

180 179 Voorbeeld We willen van Hond graag een Abstract Base Class maken! Waarom?

181 Pure virtual member function 180

182 Pure virtual member function 181 Pure virtual memberfunctie wordt in UML cursief weergegeven.

183 Abstract Base Class 182

184 Abstract Base Class 183 ABC wordt in UML cursief weergegeven.

185 184 Aggregatie implementatie  Hoe kunnen we een 0..1 aggregatie implementeren in class SintBernard ?  WhiskeyVat data member?  WhiskeyVat& data member?  WhiskeyVat* data member? Niet 0..1 maar 1. Andere naam voor een WhiskeyVat dat al bestaat. Onzin!

186 185 Aggregatie implementatie #ifndef __SintBernard_h__ #define __SintBernard_h__ class WhiskeyVat; class SintBernard { public: WhiskeyVat* heeft_om_zijn_nek; void blaf(); }; #endif

187 186 Aggregatie implementatie #ifndef __WhiskeyVat_h__ #define __WhiskeyVat_h__ class SintBernard; class WhiskeyVat { public: SintBernard* heeft_om_zijn_nek; }; #endif

188 187 Aggregatie implementatie

189 188 Aggregatie implementatie

190 189 Aggregatie implementatie #ifndef __SintBernard_h__ #define __SintBernard_h__ class WhiskeyVat; class SintBernard { public: void blaf(); private: WhiskeyVat* vat; }; #endif

191 190 Aggregatie implementatie  Hoe kunnen we een 0..5 aggregatie implementeren in class Kennel ?  array met Hond* -ers  array  vector Beter! Maar niet beschikbaar in Visual Paradigm Goed! Wel beschikbaar in Visual Paradigm, ook bruikbaar voor 0..*

192 191 Aggregatie implementatie #include using namespace std; #ifndef __Kennel_h__ #define __Kennel_h__ class Hond; class Kennel { private: std::vector inwoners; }; #endif Liever niet!

193 192 Opdracht  Schrijf een testprogramma voor de hiervoor gemaakte class Kennel.  Zet een SintBernard genaamd boris in de Kennel genaamd k.  Zet een Tekkel genaamd harry in de Kennel k.  Zet een SintBernard genaamd felix in de Kennel k.  Laat alle honden in de Kennel k blaffen.  Haal harry uit de Kennel k.  Laat alle honden in de Kennel k blaffen. Bedenk eerst welke messages je naar een Kennel moet kunnen sturen.

194 193 Uitwerking Waarom Hond& als parameter? #include #ifndef __Kennel_h__ #define __Kennel_h__ class Hond; class Kennel { private: std::vector inwoners; public: void zetIn(Hond& h); void haalUit(Hond& h); void blafAllemaal(); }; #endif

195 194 Uitwerking  Schrijf altijd eerst het testprogramma! Test Driven Development Gewenste uitvoer: #include using namespace std; #include "Hond.h" #include "SintBernard.h" #include "Tekkel.h" #include "Kennel.h" int main() { SintBernard boris; Kennel k; k.zetIn(boris); Tekkel harry; k.zetIn(harry); SintBernard felix; k.zetIn(felix); cout << "Alle honden in de kennel blaffen:" << endl; k.blafAllemaal(); k.haalUit(harry); cout << "Alle honden in de kennel blaffen:" << endl; k.blafAllemaal(); cin.get(); return 0; }

196 195 Kennel implementatie #include using namespace std; #include "Kennel.h" #include "Hond.h" void Kennel::zetIn(Hond& h) { if (inwoners.size() < 5) inwoners.push_back(&h); else cout << "Kennel is al vol!" << endl; } void Kennel::haalUit(Hond& h) { inwoners.erase(find(inwoners.begin(), inwoners.end(), &h)); } void Kennel::blafAllemaal() { for (auto hp: inwoners) hp->blaf(); }

197 Huiswerk!  Bestudeer boek: Warmer & Kleppe, Praktisch UML, 5 de editie.  en  Bestudeer dictaat:  paragraaf

198 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 16

199 198 UML diagrammen  Statische structuur van programma.  UML Klassediagram.  Dynamisch gedrag van programma.  UML Objectdiagram.  UML Use-case-diagram.  UML Sequentiediagram.  UML Communicatiediagram.  UML Toestandsdiagram.  UML Activiteitsdiagram. Use-case-diagram beschrijft het gedrag van het programma gezien vanuit de gebruikers van het programma.

200 199 UML Use-case-diagram  Wordt gebruikt voor vastleggen van de functionele eisen. Actor Systeemgrens Use-case

201 200 Use-case beschrijving NaamRekening openen ActorBaliemedewerker AannamenBaliemedewerker heeft beschikking over de NAW-gegevens van de Klant. De Klant kan zich legitimeren. Beschrijving1.De baliemedewerker maakt aan het systeem bekend dat een nieuwe rekening aangemaakt moet worden en voert de NAW-gegevens van de Klant in. 2.Als de klant een bedrijf is wordt het KvK nummer ingevoerd. 3.Het systeem controleert of de Klant al rekeningen heeft en of de Klant rood staat op een van deze rekening. In dat geval treedt een uitzondering [rood staan] op. 4.Het systeem maakt het nummer van de nieuwe rekening bekend aan de baliemedewerker. Uitzonderingen[rood staan] De baliemedewerker kan naar de use-case Geld storten overgaan om de Klant de gelegenheid te geven het tekort aan te vullen. Als het tekort is aangevuld wordt de use-case vervolgd bij stap 3. ResultaatDe Klant heeft minstens 1 rekening.

202 201 Use-case beschrijving

203 202 UML diagrammen  Statische structuur van programma.  UML Klassediagram.  Dynamisch gedrag van programma.  UML Use-case-diagram.  UML Sequentiediagram.  UML Communicatiediagram.  UML Toestandsdiagram.  UML Activiteitsdiagram. Sequentiediagram laat zien in welke volgorde objecten elkaar berichten sturen. Communicatiediagram laat zien welke objecten elkaar berichten sturen.

204 203 Sequentiediagram  Boek (p.119): wekker stuurt boodschap zoem naar :Gebruiker Actor Object Tijd Boodschap Actor kan boodschap sturen naar object. Object kan boodschap sturen naar actor, andere objecten en naar zichzelf.

205 Sequentiediagram  Verbeterde versie: 204

206 Communicatiediagram Bevat dezelfde informatie als een sequentiediagram. 205

207 Conditionele boodschappen 206

208 207 Conditionele boodschappen

209 Iteratie van boodschappen 208

210 209 Iteratie van boodschappen void Kennel::blafAllemaal() { for (auto hp: inwoners) hp->blaf(); } Visual Paradigm kan geen Sequence Diagram tekenen vanuit C++ code. Visual Paradigm kan geen code (ook geen Java) genereren vanuit een Sequence Diagram

211 Boodschap aan jezelf 210

212 211 Constructor

213 212 Voorbeeld (vervolg...)

214 213 Opgave  Maak een sequentiediagram waarin een testprogramma de volgende acties uitvoert:  Zet een SintBernard genaamd boris in de Kennel genaamd k.  Zet een Tekkel genaamd harry in de Kennel k.  Laat alle honden in de Kennel k blaffen.

215 Uitwerking 214

216 Huiswerk!  Bestudeer boek: Warmer & Kleppe, Praktisch UML, 5 de editie.  Hoofdstuk 8 (behalve en 8.7.6).  Hoofdstuk 10 (behalve 10.7).  Opgaven bij H8, H10 (zie BB).  Maak opgaven van voorgaande sheets:  Sequentiediagram. 215

217 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 17

218 217 UML diagrammen  Statische structuur van programma.  UML Klassediagram.  Dynamisch gedrag van programma.  UML Use-case-diagram.  UML Sequentiediagram.  UML Communicatiediagram.  UML Toestandsdiagram.  UML Activiteitsdiagram. Toestandsdiagram laat de toestanden en toestandsovergangen van een klasse zien.

219 218 Toestandsdiagram  Toestand van een WhiskeyVat Worden we hier veel wijzer van?

220 219 Toestandsdiagram

221 220 Toestandsdiagram #include "WhiskyVat_sm.h" class WhiskyVat { private: WhiskyVatContext _fsm; public: WhiskyVat(): _fsm(*this) { } WhiskyVatContext& getContext() { return _fsm; } void maakVol() { _fsm.maakVol(); } void maakLeeg() { _fsm.maakLeeg(); } };

222 221 Toestandsdiagram #include "WhiskyVat.h" void state_Leeg(WhiskyVat *aWhiskyVat) { printf("Please select transition:\n"); printf("1. maakVol\n"); printf("0. quit\n"); int choice; scanf("%d", &choice); switch (choice) { case 1: aWhiskyVat->maakVol(); break; case 0: exit(0); } void state_Vol(WhiskyVat *aWhiskyVat) { /* idem */

223 222 Toestandsdiagram int main(int argc, char **argv) { WhiskyVat lWhiskyVat; while (true) { printf("Current state: %s\n", lWhiskyVat.getContext().getState().getName()); if (&lWhiskyVat.getContext().getState() == &WhiskyVatFSM::Leeg) { state_Leeg(&lWhiskyVat); } else if (&lWhiskyVat.getContext().getState() == &WhiskyVatFSM::Vol) { state_Vol(&lWhiskyVat); }

224 223 Toestandsdiagram Current state: WhiskyVatFSM::Leeg Please select transition: 1. maakVol 0. quit 1 Current state: WhiskyVatFSM::Vol Please select transition: 1. maakLeeg 0. quit 1 Current state: WhiskyVatFSM::Leeg Please select transition: 1. maakVol 0. quit 0

225 224 Opgave  Teken een toestandsdiagram dat het login proces van een online bankapplicatie modelleert.  Om in te loggen moet de klant een rekeningnummer en een pincode invoeren in twee invoervelden.  In deze invoervelden mogen alleen cijfers worden ingevoerd.  Wisselen tussen invoervelden kan met de TAB toets.  Als de ENTER toets wordt ingedrukt dan moeten het ingevoerde rekeningnummer en pincode worden gecontroleerd.  Geldig: start transactie.  Ongeldig: geef foutmelding en wis invoervelden.  Als op de ESC toets wordt gedrukt moet de login procedure worden afgebroken.

226 225 Uitwerking

227 226 UML diagrammen  Statische structuur van programma.  UML Klassediagram.  Dynamisch gedrag van programma.  UML Use-case-diagram.  UML Sequentiediagram.  UML Communicatiediagram.  UML Toestandsdiagram.  UML Activiteitsdiagram. Een Activiteitsdiagram laat een stroom van activiteiten zien.

228 Activiteitsdiagram 227 Swimlane Start Activiteit Beslispunt Samenkomst Splitsing Synchronisatie Guard Einde

229 Huiswerk!  Bestudeer boek: Warmer & Kleppe, Praktisch UML, 5 de editie.  Hoofdstuk 12.  Hoofdstuk 15.  H12 en H15 (zie BB).  Maak opgaven van voorgaande sheets:  Toestandsdiagram. 228

230 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 18

231 230 Globaal en lokaal geheugen int global; void f(int parameter) { int local1; //... } void main() { int local2; //... f(local2); } De compiler bepaalt wanneer variabelen worden aangemaakt en opgeruimd.

232 231 Dynamisch geheugen  Je kunt ook zelf beslissen wanneer een variabele (object) wordt aangemaakt en opgeruimd. Tekkel* hp = new Tekkel; hp->blaf(); delete hp; Reserveer geheugenruimte (bij Operating System) Geef geheugenruimte vrij (aan Operating System)

233 232 size_t s; cout << "Hoeveel Tekkels wil je? "; cin >> s; Tekkel* c = new Tekkel[s]; for (size_t i = 0; i < s; ++i) c[i].blaf(); delete[] c; size_t s; cout << "Hoeveel Tekkels wil je? "; cin >> s; Tekkel a[s]; for (auto t: a) t.blaf(); Dynamische array  Het geheugen wordt aangevraagd als het programma runt  grootte hoeft niet bij compileren bekend te zijn.  Statisch:  Dynamisch: const size_t s = 5; Tekkel a[s]; for (auto t: a) t.blaf(); Error: expected constant expression Range-based for werkt hier niet.

234 233 Dynamisch geheugen  Krachtig:  Je bepaalt zelf wanneer geheugen wordt aangemaakt of vrijgegeven.  Gevaarlijk:  Memory corruption.  delete te veel of delete van verkeerde pointer.  Memory leak.  delete vergeten.  Undefined behaviour.  gebruik van een deleted variabele. Gebruik zoveel mogelijk standaard componenten zoals std::vector

235 234 Dynamische std::vector  Het geheugen wordt aangevraagd als het programma runt  grootte hoeft niet bij compileren bekend te zijn.  Dynamisch: #include using namespace std; vector ::size_type s; cout << "Hoeveel Tekkels wil je? "; cin >> s; vector v(s); for (Tekkel t: v) t.blaf();

236 235 Constructor  Wordt door de compiler aangeroepen als een variabele gemaakt wordt. class Breuk { public: Breuk(); Breuk(int t); Breuk(int t, int n); int teller() const; int noemer() const; void plus(Breuk b); private: int boven; int onder; void normaliseer(); }; void main() { Breuk a, b(-2), c(21,-9); //... }

237 236 Destructor  Wordt door de compiler aangeroepen als een variabele verwijderd wordt. class Breuk { public: Breuk(); Breuk(int t); Breuk(int t, int n); ~Breuk(); int teller() const; int noemer() const; void plus(Breuk b); private: int boven; int onder; void normaliseer(); }; void main() { Breuk a, b(-2), c(21,-9); //... } Breuk::~Breuk() { cout << "De breuk met teller " << boven << " en noemer " << onder << " is overleden." << endl; }

238 237 Constructor en destructor  Compiler roept de constructor en destructor automatisch aan. { Breuk a(21,-9); //... } Reserveer geheugen op de stack voor a en roep constructor a.Breuk(21,-9) aan Roep destructor a.~Breuk() aan en geef geheugen van a weer vrij

239 238 Constructor en destructor  Compiler roept de constructor en destructor automatisch aan. { Breuk* bp = new Breuk(21,-9); //... delete bp; //... } Reserveer geheugen op de heap en roep constructor Breuk(21,-9) aan Roep destructor ~Breuk() aan en geef geheugen weer vrij

240 239 Gratis bij elke class!  constructor zonder argument (default constructor). Deze constructor roept de default constructor aan van alle data members.  copy constructor. Deze constructor roept de copy constructor aan van alle data members.  assignment operator ( operator= ). Deze assignment operator roept de assignment operator aan van alle data members.  destructor. Deze destructor roept de destructor aan van alle data members. Je kunt al deze functies ook zelf definiëren!

241 240 Default destructor probleem  De automatisch door de compiler aangemaakte default destructor is niet virtual. class Hond { public: virtual void blaf() = 0; }; class SB: public Hond { private: Whisky vat; public: SB() { vat.maakVol(); } virtual ~SB () { vat.maakLeeg(); } virtual void blaf() override { cout << "Woef woef" << endl; } }; int main() { Hond* Boris(new SB); Boris->blaf(); delete Boris; } ~SB() wordt niet aangeroepen!

242 241 Virtual destructor  Als een class nu of in de toekomst als basis class gebruikt wordt dan moet de destructor virtual zijn zodat van deze class afgeleide classes via een polymorphic pointer gedelete kunnen worden. class Hond { public: virtual ~Hond() = default; virtual void blaf() = 0; }; class SintBernard: public Hond { public: virtual ~SintBernard(); }; C++11

243 242 Huiswerk!  Voeg in practicum opgave 2b een destructor toe die meldt dat een Tijdsduur is overleden.  Verklaar de uitvoer.  Verander nu in opgave 2b elke const Tijdsduur& door een Tijdsduur.  Verklaar de wijzigingen in de uitvoer.  Bestudeer dictaat:  Hoofdstuk 5 t/m 5.4.

244 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 19

245 244 Aggregatie implementatie Geef de implementatie van de constructor en de destructor. class SintBernard: public Hond { public: SintBernard(); virtual ~SintBernard(); virtual void blaf() override; private: WhiskeyVat* vat; };

246 SintBernard::SintBernard(): vat(new WhiskeyVat) { vat->maakVol(); } virtual ~ SintBernard::SintBernard() { vat->maakLeeg(); delete vat; } virtual void SintBernard::blaf() { cout << "WOEF WOEF" << endl; } 245 Implementatie Aangemaakt met new vat :SintBernard :WhiskeyVat

247 246 ? Copy constructor SintBernard a; SintBernard b(a); SintBernard::SintBernard(): vat(new WhiskeyVat) { vat->maakVol(); } Default copy constructor: kopieert alle data members Dit is niet goed! We moeten zelf een copy constructor definiëren. a vat b ?

248 247 Copy constructor  Gewenst resultaat: a vat b

249 248 Copy constructor  Kun je ook een SintBernard in plaats van een const SintBernard& als parameter gebruiken?  Nee! Want dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen, maar dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen, maar dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen maar, dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen maar, dan... SintBernard::SintBernard(const SintBernard& r): Hond(r), vat(0) { if (r.vat != 0) vat = new WhiskeyVat(*(r.vat)); }

250 249 operator= SintBernard a; SintBernard b; b = a; Default assignment operator: assigned alle data members b.vat = a.vat; Dit is niet goed! We moeten zelf een operator= definiëren. a vat b

251 250 operator=  Gewenst resultaat: a vat b

252 SintBernard& SintBernard::operator=(SintBernard r) { std::swap(vat, r.vat); return *this; } SintBernard& SintBernard::operator=(const SintBernard& r) { SintBernard t(r); std::swap(vat, t.vat); return *this; } 251 operator=  Kun je ook een SintBernard in plaats van een const SintBernard& als parameter gebruiken?  Ja! Er wordt dan een overbodig kopietje gemaakt.  Ja!!! Het maken van het kopietje t is dan overbodig!  Wat is nut van SintBernard& return type en return *this ?  a = b = c;

253 252 Wanneer zelf definiëren?  Een class moet een zelf gedefinieerde copy constructor, operator= en destructor bevatten als:  die class een pointer bevat en  als bij het kopiëren van een object van de class niet de pointer, maar de data waar de pointer naar wijst moet worden gekopieerd en  als bij een toekenning aan een object van de class niet de pointer, maar de data waar de pointer naar wijst moet worden toegekend en  als bij het opruimen van een object van de class niet alleen de pointer, maar ook de data waar de pointer naar wijst moet worden opgeruimd.

254 253 Huiswerk!  Bestudeer dictaat:  Paragraaf 5.5 t/m 5.10.

255 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 20

256 255 Memberfuncties en data members  Elk object heeft zijn eigen data members terwijl de memberfuncties door alle objecten van een bepaalde class "gedeeld" worden. class Hond { public: Hond(const string& n); void blaf(); private: string naam; }; Hond::Hond(const string& n): naam(n) { } void Hond::blaf() { cout << naam << " zegt: WOEF" << endl; }

257 256 Memberfuncties en data members  We willen bijhouden hoeveel objecten van de class Hond er op een bepaald moment bestaan. int aantalHonden = 0; //dit is een globale variabele class Hond { public: Hond(const string& n); ~Hond(); void blaf(); private: string naam; }; Hond::Hond(const string n): naam(n) { ++aantalHonden; } Hond::~Hond() { --aantalHonden; }

258 257 static  Een static data member is een onderdeel van de class en wordt door alle objecten van de class gedeeld. class Hond { public: Hond(const string& n); ~Hond(); void blaf(); static int aantal(); private: string naam; static int aantalHonden; };

259 258 static  Een static data member is een onderdeel van de class en wordt door alle objecten van de class gedeeld. int Hond::aantalHonden = 0; Hond::Hond(const string& n): naam(n) { ++aantalHonden; } Hond::~Hond() { --aantalHonden; } int Hond::aantal() { return aantalHonden; } void Hond::blaf() { cout << naam << " zegt: WOEF" << endl; }

260 259 static memberfuncties  Twee manieren van aanroepen:  direct via de classnaam: class_naam::member_functie_naam(parameters) Voorbeeld: cout << Hond::aantal() << endl;  via een object van de class: object_naam.member_functie_naam(parameters) Voorbeeld: cout << h1.aantal() << endl;  Beperkingen t.o.v. een gewone memberfunctie:  Een static memberfunctie heeft geen receiver (ook niet als hij via een object aangeroepen wordt).  Een static memberfunctie heeft dus geen this pointer.  Een static memberfunctie kan dus geen "gewone" memberfuncties aanroepen en ook geen "gewone" data members gebruiken.

261 260 static  Een static data member is een onderdeel van de class en wordt door alle objecten van de class gedeeld. UML boek: paragraaf class Hond { public: Hond(const string& n); ~Hond(); void blaf(); static int aantal(); private: string naam; static int aantalHonden; };

262 261 static  static in Visual Paradigm:

263 262 Huiswerk!  Bestudeer boek:  Paragraaf  Bestudeer dictaat:  Paragraaf 6.1.  Bestudeer BB:  Extra voorbeelden over inheritance en polymorphisme.

264 263 Overzicht stof OGOPRG  Dictaat:  Hoofstuk 1 t/m 6 (alleen 6.1, de rest van hoofdstuk 6 is voor de “liefhebbers”).  Boek:  Hoofdstuk 1 en 2.  Hoofdstuk 4 (behalve 4.4.1, 4.4.3, 4.4.5, 4.4.6, 4.4.7, t/m , , en 4.6.9).  Hoofdstuk 8 (behalve en 8.7.6).  Hoofdstuk 10 (behalve 10.7).  Hoofdstuk 12.  Hoofdstuk 15.  Opgaven! Zie BB.

265 264 Afronden practicum  Deze week klaar! Anders onvoldoende.  Herkansing:  Alleen opdracht 4 nog niet klaar: Per inleveren bij vóór 17 april  Nog meer opdrachten niet klaar: Aftekenen op 23 april. Afspraak maken voor einde van deze week!

266 Objectgeoriënteerd Programmeren in C++ OGOPRG Les 21

267 266 ADT Array  De grootte van een Array kan tijdens run-time bepaald worden.  Bij het gebruik van [] wordt gecontroleerd of de index binnen de grenzen van de Array ligt.  Implementatie van Array : Aangemaakt met new 4 size data

268 267 ADT Array class Array { public: explicit Array(int s); Array(const Array& r); Array& operator=(const Array& r); ~Array(); int& operator[](int index); const int& operator[](int index) const; int length() const; bool operator==(const Array& r) const; bool operator!=(const Array& r) const; //... // Er zijn vele uitbreidingen mogelijk. private: int size; int* data; };

269 268 ADT Array Array::Array(int s): size(s), data(new int[s]) { } Array::~Array() { delete[] data; } Aangemaakt met new 4 size data ???? 0123

270 269 ? ? 0149 ???? ? ? Copy constructor Array a(4); for (int j = 0; j < a.length(); ++j) { a[j] = j * j; // vul a met kwadraten } Array b(a); Array::Array(int s): size(s), data(new int[s]) { } 4 size data size data a b Default copy constructor: kopieert alle data members Dit is niet goed! We moeten zelf een copy constructor definiëren.

271 270 Copy constructor  Gewenst resultaat: 4 size data b 4 size data a

272 271 Copy constructor  Kun je ook een Array in plaats van een const Array& als parameter gebruiken?  Nee! Want dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen, maar dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen, maar dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen maar, dan moet er een kopietje worden gemaakt en dan wordt de copy constructor aangeroepen maar, dan moet er een kopietje worden gemaakt en dan... Array::Array(const Array& r): size(r.size), data(new int[r.size]) { for (int i = 0; i < size; ++i) data[i] = r.data[i]; }

273 272 operator= Array a(4); Array b(a.length()); for (int j = 0; j < a.length(); ++j) { a[j] = j * j; // vul a met kwadraten b[j] = j * a[j]; // vul b met derde machten } b = a; 4 size data b 4 size data a Default assignment operator: assigned alle data members b.size = a.size; b.data = a.data; Dit is niet goed! We moeten zelf een operator= definiëren.

274 273 operator=  Gewenst resultaat: 4 size data b size data 4 size data a

275 Array& Array::operator=(Array r) { std::swap(data, r.data); std::swap(size, r.size); return *this; } 274 operator=  Kun je ook een Array in plaats van een const Array& als parameter gebruiken?  Ja! Er wordt dan een overbodig kopietje gemaakt.  Ja!!! Het maken van het kopietje t is dan overbodig!  Wat is nut van Array& return type en return *this ?  a = b = c; Array& Array::operator=(const Array& r) { Array t(r); std::swap(data, t.data); std::swap(size, t.size); return *this; }

276 275 Wanneer zelf definiëren?  Een class moet een zelf gedefinieerde copy constructor, operator= en destructor bevatten als:  die class een pointer bevat en  als bij het kopiëren van een object van de class niet de pointer, maar de data waar de pointer naar wijst moet worden gekopieerd en  als bij een toekenning aan een object van de class niet de pointer, maar de data waar de pointer naar wijst moet worden toegekend en  als bij het opruimen van een object van de class niet alleen de pointer, maar ook de data waar de pointer naar wijst moet worden opgeruimd.

277 276 ADT Array versus C array  Voordelen ADT Array :  Bij aanmaken mag de grootte een variabele zijn.  Bij gebruik [] wordt de index gecontroleerd.  Nadelen ADT Array :  Je kunt er alleen int egers in opslaan! Oplossing?

278 277 Template class Array template class Array { public: explicit Array(int s); Array(const Array & v); Array & operator=(const Array & r); ~Array(); T& operator[](int index); const T& operator[](int index) const; int length() const; bool operator==(const Array & r) const; bool operator!=(const Array & r) const; //... // Er zijn vele uitbreidingen mogelijk. private: int size; T* data; }; template Array ::Array(int s): size(s), data(new T[s]) { }

279 278 Template class Array //... int i; cout << "Hoe groot wil je de Array's "; cin >> i; Array a(i); for (int j = 0; j < v.length(); ++j) a[j] = sqrt(j); // Vul a met wortels cout << "a[12] = " << a[12] << endl; Array b(i); for (int j = 0; j < b.length(); ++j) b[j] = j * j; // Vul b met kwadraten cout << "b[12] = " << b[12] << endl; //...

280 279 ADT Array versus std::Array  Voordelen ADT Array :  Bij aanmaken mag de grootte een variabele zijn.  Bij gebruik [] wordt de index gecontroleerd.  Voordelen std:: Array :  Grootte is een template parameter en hoeft dus niet opgeslagen te worden.  Je kunt range-based for gebruiken om door de std::Array te lopen.  Je kunt een std::Array initializeren met { … } Oplossing?

281 280 ADT Array uitbreidingen C++11 #include template class Array { public: //... // Support for initializer list Array(initializer_list list); // Support for range-based for T* begin(); const T* begin() const; T* end(); const T* end() const; private: int size; T* data; };

282 281 ADT Array uitbreidingen C++11 template Array ::Array(initializer_list l): size(list.size()), data(new T[size]) { auto listIter = list.begin(); for (int i = 0; i < size; ++i) { data[i] = *listIter++; } template T* Array ::begin() { return data; } template const T* Array ::begin() const { return data; } template T* Array ::end() { return data + size; } template const T* Array ::end() const { return data + size; }

283 282 ADT Array uitbreidingen C++11 //... Array v = {1, 2, 3, 4}; for (auto e: v) { cout << e << " "; } cout << endl; //...

284 Objectgeoriënteerd Programmeren in C++ Terugblik practicum

285 284 Inhoud  Objectgeoriënteerd Programmeren in C++.  responsibility driven design (ontwerpen uitgaande van verantwoordelijkheden).  information hiding (het afschermen van informatie door middel van het scheiden van interface en implementatie).  abstraction (het afschermen van complexiteit door middel van het scheiden van interface en implementatie).  inheritance (het mogelijk maken van een nieuwe vorm van hergebruik,... is een... in plaats van... heeft een...).  polymorphism (veelvormigheid mogelijk gemaakt door dynamic binding).  Objectgeoriënteerd Ontwerpen met UML.  klasse- en objectdiagrammen.  use-case-diagram.  sequence- en collaborationdiagrammen.  toestands- en activiteitendiagrammen.

286 Herbruikbaarheid  Practicumopdracht 1  Hier heb je gezien dat de class std::string een eenvoudig te (her)gebruiken component is.  Een object van het type std::string :  Slaat een character string op (private data members).  Heeft interface (public memberfuncties) waarmee:  Informatie over de opgeslagen string kan worden opgevraagd ( find ).  De opgeslagen string kan worden gewijzigd ( erase ).  Practicumopdracht 2a  Hier heb je zelf een ADT (Abstract DataType = herbruikbare component) Tijdsduur gemaakt.  Practicumopdracht 2b  Hier heb je door operator overloading toe te passen de herbruikbaarheid vergroot. 285

287 Aanpasbaarheid  Practicumopdracht 2c  Hier heb je de implementie van de classs Tijdsduur gewijzigd (slaat alleen nog minuten op) zonder de interface aan te passen.  Alle code die gebruik maakt van de component Tijdsduur merkt hier niets van en hoeft niet aangepast te worden!  Beide implementaties hebben hun sterkte:  Implementatie van opdracht 2b kan sneller printen.  Implementatie van opdracht 2c kan sneller rekenen en gebruikt minder geheugen.  Doordat beide implementaties dezelfde interface hebben kan een gebruiker van de component (een programmeur) altijd nog wisselen van implementatie. 286

288 Herbruikbaarheid  Practicumopdracht 2d  Hier heb je de code van de component Tijdsduur opgenomen in twee aparte files Tijdsduur.h en Tijdsduur.cpp  De herbruikbaarheid is hierdoor vergroot (component kan gebruikt worden door Tijdsduur.h te includen en Tijdsduur.cpp mee te linken).  De aanpasbaarheid is hierdoor vergroot (wisselen van implementatie kan nu door wisselen van files).  Je kan de component nu verspreiden zonder de source code vrij te geven. Door alleen Tijdsduur.h en een gecompileerde versie van Tijdsduur.cpp te verspreiden. 287

289 Uitbreidbaarheid  Practicumopdracht 3b en 3c  Hier heb je gezien dat door het gebruik van overerving het in opdracht 3a gemaakte programma eenvoudig is uit te breiden met een nieuwe soorten werknemers: Stukwerker en Manager.  De polymorphic functie printMaandSalaris(const Werknemer& w) hoeft niet aangepast te worden.  Je hoeft alleen de “verschillen” te programmeren. Het “gemeenschappelijke” erf je over vanuit de basisklasse Werknemer.  Als het goed is heb je de basisklasse Werknemer abstract gemaakt om slicing te voorkomen. 288


Download ppt "0 Inhoud Les 1 Les 3 Les 4 Les 6 Les 7 Les 9 Les 10 Les 12Les 15 Les 13Les 16Les 19 Les 18Les 21 Les 2Les 5Les 8Les 11Les 14Les 17Les 20."

Verwante presentaties


Ads door Google