Hoofdstuk 1: Inleiding Objectoriëntatie: 1. Objecten & klassen: samenwerking van ≠ componenten om bepaald doel te bereiken; herbruikbaarheid. 2. Encapsulation: afschermen gedragingen en kenmerken van de buitenwereld (//datahiding). 3. Boodschappen: uitwisselen boodschappen (//oproepen van membermethoden). 4. Inheritance: overerving van eigenschappen. 5. Polymorfisme: gebruik van dezelfde naam voor verschillende methodes is mogelijk.
Hoofdstuk 2: Klassen en objecten Datahiding: afschermen van implementatiedetails. Naar de buitenwereld toe enkel interfaces.
Toegang: • • •
Java: public, private, protected (voor overerving!). Default: public! C#: (assembly = equivalent van package in Java) private, public, protected en internal. Default: private. C++: protected, private, public. Default: private. Mogelijkheid om friends te definiëren toegang van de “friend” tot alle private attributen en methoden.
Objecten: • •
C# en Java: steeds via verwijzingen (soort pointers) C++: object ofwel maken, ofwel met dynamische geheugentoewijzing zoals in C. Overloading van constructoren is mogelijk (= schrijven van ≠ soorten constructoren).
Returnwaarden: • • •
Java: steeds call by reference voor objecten C++: default call by value (objecten worden gekopieerd). Call by reference mogelijk door toevoeging &. Wijziging vermijden door toevoegen const. Ook mogelijk door pointers door te geven. C#: call by value en call by reference mogelijk op objecten én primitieve datatypes.
Garbage collection: • • •
C++: dynamische aangemaakte variabelen achteraf vernietigen + destructoren niet vergeten! Moment van garbage collection gekend en controlleerbaar. C#: garbage collector heeft eigen wil. Java: methode void finalize() throws Throwable opgeroepen alvorens vernietiging.
Geneste klassen/inner classes: =klasse binnen klasse. Mogelijk in C++, C# en Java. Af te raden in OO (herbruikbaarheid!). Object in een klasse is OK, niet klasse in klasse.
Statische attributen en methoden: Oproepen op volgende manier: • Java: KlasseNaam.statischeMember(…) • C++: KlasseNaam::statischeMember(…) Statische variabelen enkel initialiseerbaar BUITEN de klasse.
This: Java en C#: this.waarde = waarde; C++: is een pointer (!) naar het adres van het object waar men mee bezig is: this->waarde = waarde;
Operator overloading: Java: onmogelijk C++: stel operator @ • Binaire operatoren (bvb: a@b): a.operator@(b) of operator@(a,b) (laatste als friend declareren, is niet statisch!). • Unaire operatoren (bvb: a@ of @a): o Voor @a: a.operator@() of operator@(a) (laatste als friend declareren, is niet statisch!) o Voor a@: a.operator@(dummyInt) of operator@(a,dummyInt) (laatste als friend declareren, is niet statisch!) • Indexeringsoperator ([]): werken met arrays pointers pas op! • istream en ostream (<<): na aaneenkoppeling moet er een stream als resultaat terug gegeven worden! C#:
• • •
Enkel via statische methoden Unaire operatoren: zelfde methode [] kan niet overladen worden
Dynamisch geheugen in objecten (C++): Altijd maken (verduidelijking: illustratie op volgende bladzijde): • Copy constructor: bij call-by value wordt het object gekopieerd! Default copy constructor gaat niet goed om met pointers. Op ogenblik dat operator= wordt automatisch een kopie gemaakt van hetgeen doorgegeven wordt pointers gekopieerd, geheugenruimte waar naar verwezen wordt niet! • Assignment operator (operator=(…)): default assignment (x2=x1;) operator stelt pointer gelijk aan zijn overeenkomstige wijzen naar zelfde geheugenruimte problemen! • Destructor: default destructor ruimt enkel pointer op memory leak!
rij x2 aantal
4 6
rij x1 aantal
4
Kunnen opvangen: • x1=x2=x3; • x1=x1; • Opruim regelen achteraf geheugen waar pointer naar verwijst!
Hoofdstuk 3: Overerving • •
Bij gemeenschappelijke kenmerken tussen klassen Aanpassing van een bestaand softwaresysteem
Basisprincipe: subklassen overerven van superklassen • • •
Java: gebruik van extends. C++: gebruik van “:” C#: exact zelfde als Java, maar “:” in plaats van extends.
Default constructoren/destructoren • •
Constructoren: eerst die van basisklasse, dan die van afgeleide klasse opgeroepen. Destructoren: eerst die van afgeleide klasse, dan die van basisklasse opgeroepen.
Constructoren met parameters • • •
Java: gebruik van super(parameter) in de constructor. Deze altijd als eerste aanroepen! C#: expliciete aanroep in declaratie van constructor: Afgeleide(int waarde_uit_basis,int w2): base(waarde_uit_basis); C++: expliciete aanroep in declaratie van constructor: Afgeleide(int waarde_uit_basis,int w2) : Basis(waarde_uit_basis).
Public, protected en private Permissies versoepelen gaat nooit, verstrengen wel! • Java: default public overerving; protected leden zijn bereikbaar vanuit afgeleide klassen en vanuit klassen in zelfde package.
•
C#: protected leden zijn enkel bereikbaar vanuit afgeleide klassen; overerving is default public • C++: overerving is default private; protected leden zijn enkel bereikbaar vanuit afgeleide klassen Hebben toegang public protected private tot ~ members? Member en friend ja ja ja functies Functies van ja ja nee afgeleide klassen Andere functies ja nee nee Inheritance Public Protected Private
Public members Public Protected Private
Protected members Protected Protected Private
Private members Private Private Private
Slicing Java, C#: • Referentie basistype object van afgeleide klasse; Enkel nog toegang tot basisattributen! C++: • Object basis klasse gelijk stellen aan Object afgeleide klasse: Afgeleide af(parameters); Basis ba = af; Enkel basisattributen gekopieerd! • Pointer van type basisklasse naar adres afgeleid object: Afgeleide af(parameters); Basis* ba = ⁡ Enkel nog toegang tot basisattributen!
Hiding (niet voor privates!) Java: • Atributen • Statische methoden - Zelfde parameterlijst en zelfde returntypes - Minstens zelfde toegankelijkheid • Benadering van attribuut uit basisklasse met super.attribuut C++: • Attributen • Benadering met Basisklasse::attribuut C#: • • • •
Attributen Instantiemethoden new gebruiken om compiler duidelijk te maken dat we werkelijk het attribuut willen “verbergen” en dus een nieuw binnen het object wensen aan te maken, anders compiler warning! Benadering met base.attribuut
Overriding (
treedt op bij slicing!!)
Java: • Instantiemethodes (Afgeleide klasse overschrijft basismethode!) - Zelfde naam, parameterlijst en returntype! • basisObject = afgeleidObject; basisObject wijst enkel nog naar basisgedeelte. Instantiemethodes van afgeleide klasse zijn wel nog van toepassing (dynamic binding = default in java)!! C++: • basisObject = afgeleidObject; enkel basisdeel van het afgeleidObject wordt gekopieerd opereren onafhankelijk van elkaar overridden (afgeleide) methodes zijn hier niet van toepassing Met pointers werken! BasisObject* basisObject = new AfgeleidObject(parameter); • Niet vergeten te deleten!!
Dynamic binding •
Statische binding/binding @ compile-time: Voor het runnen is reeds beslist welke instantiemethode te gebruiken! 1. Java: default 2. C++: voor de basisfunctie steeds virtual zetten BasisObject* basisObject = new AfgeleidObject(parameter); basisObject.doeIets(); Nog steeds zal afgeleide methode aangeroepen, ook al is afgeleid object “gereduceerd” tot basisobject!! In geval van interne dynamische geheugenallocatie steeds ook voor destructor virtual zetten!! virtual ~basisObject(param) {…}
Abstracte klassen • • • •
Gemeenschappelijke kenmerken groeperen Objecten aanmaken niet mogelijk Afgeleide klassen moeten methoden implementeren Niet alle methoden zijn noodzakelijk abstract!
1. Java: abstract voor de klassenaam zetten; abstract voor elke nietgeïmplementeerde (!) methode: abstract class Klasse { abstract void methode(); void doeIets() {System.out.println(“Iets!”);} } 2. C++: minstens 1 “pure virtual class” schrijven (=0 in declaratie): class Klasse { virtual void doeIets()=0; } 3. C#: zie Java
Multiple Inheritance C#: geen echte multiple inheritance! C++: • Syntax: Afgeleide: public Basis1, private Basis2{ … } • Probleem 1: basisklassen hebben attributen/methoden met zelfde naam oplossing: anders benaderen! Niet b.doeIets(); maar b.Basis1::doeIets(); of b.Basis2:doeIets(); • Probleem 2 (=“Diamond Problem”, zie figuur links): class Persoon {…}; class Personeelslid : public Persoon {..}; class Klant : public Persoon {…}; class PersoneelKlant: public Klant, public Personeelslid {…}; Gevolg: objecten van PersoneelKlant hebben twee deelobjecten van Persoon conflicten! Oplossing: class Persoon {…}; class Personeelslid : public virtual Persoon {..}; class Klant : public virtual Persoon {…}; class PersoneelKlant: public Klant, public Personeelslid {…}; Personeelslid en Klant kunnen enkel default constructor gebruiken van Persoon geen constructor met parameters aanpassen in constructor van PersoneelKlant: class PersoneelKlant: public Klant, public Personeelslid { public: PersoneelKlant(int nr,string naam):Persoon(naam), Klant(nr,naam),Personeelslid(nr,naam) {…} … }; Java: Interfaces! • Bevatten eigenschappen (enkel declaratie!) die moeten (!) worden ingevuld door de implementerende klassen (implements)! • Kan geen objecten hebben Maar vb in Java: Interface List… Class ArrayList implements List… List lijst = new ArrayList(…); is mogelijk! Enkel eigenschappen van de interface zijn bereikbaar, niet die van de klasse ArrayList! (Implementatie van interface List zorgt er bvb voor dat het mogelijk is om elementen te gaan ordenen… • Single inheritance maar implementatie van meerdere interfaces mogelijk! • Interface kan erven van andere interface (extends)
•
Kan geen attributen hebben, enkel constanten
Vragen 1. Specialisatie (afgeleide klassen) – aggregatie (object van Basis als attribuut van Afgeleide opnemen): specialisatie waar mogelijk, aggregatie waar mogelijkheden voor overerving worden ingeperkt. 2. Beperking van public toegang naar protected gebruikt wanneer ongewenst is dat externe functies toegang hebben tot attributen enkel afgeleide functies en member- en friendfuncties 3. Voorbehoud van toegang voor member- en friendfuncties. Realisatie door gebruik van aggregatie (zie 1) met private toegang! 4. Zie labo’s 5. Als ze private zijn heeft een afgeleide klasse sowieso geen toegang tot attributen of methodes van de basisklasse…
Hoofdstuk 4: Interfaces Hoofdstuk 5: Generieke datatypes Templates in C++ •
Voorbeeld van een template voor functies: #include
using namespace std; template void verwissel(T & x, T & y) { T temp; temp = x; x = y; y = temp; } template T som(T x, T y) { return x+y; } template T verschil(T x,T y) { return x-y; } int main() { int x = 4; int y = 3; cout<<x<<" "<
Belangrijk: op voorhand operatoren overloaden! Tijdens compileren overloopt compiler volgende stappen: 1. Is er een methode met identieke naam en identieke parameterlijst? 2. Is er een template met methode met correcte parameterlijst? 3. is er een template met methode waar automatische conversie op toegepast kan worden? • Templates voor klassen (voorbeeld: stack)
•
#include #include <string> using namespace std; template class stack { private: T* rij; int grootte, wijzer; public: stack(int g) { grootte = g; rij = new T[grootte]; wijzer = 0; } ~stack() { delete [] rij; } void push(T w) { rij[wijzer++] = w; } T pop() { return rij[--wijzer]; } void print() { int i; for(i=0;i<10;i++) { cout<pop()<<endl; } } }; Overerving 1. Template die overerft van een template template class NogEenStapel : Stapel {…} 2. Niet-template die overerft van een template template class Stringstapel: Stapel<string> {…}
Templates in Java en al de rest Kijk verder in cursus!