De laatste essentiele dingen
Classes ◦ Syntax ◦ Constructors & Destructors Header & Source Files ◦ Waar gebruiken we dit voor Compiler Theorie ◦ De essentiele theorie
Verzameling van gerelateerde variablen en functies Kunnen geinstancieerd worden tot een object Hetzelfde idee als in C#
class monster { private: float posX,posY; int health; public: monster() { health = 100; } void setPos(float x, float y) { posX = x; posY = y; } int damage(int attackPower) { health -= attackPower; return health;} };
Class begint met keyword class Staat in zijn eigen scope {}; ◦ Vergeet niet de scope af te sluiten met ; Access modifier wordt aangegeven met een label! (public:, protected:, private:)
class monster { private: float posX,posY; int health; public: monster() { health = 100; } void setPos(float x, float y) { posX = x; posY = y; } int damage(int attackPower) { health -= attackPower; return health;} };
Onderdelen van een class noemen we members ◦ Variabelen binnen een class zijn member variabelen ◦ Functies binnen een class zijn member functions. Deze noemen we ook wel methods Behalve de constructor heeft elke method een return type ◦ Hetzelfde als in C#
Speciaal soort class, met keyword struct Vrijwel niet verschillend van een class ◦ Standaard access modifier class is private ◦ Standaard access modifier struct is public Semantische betekenis verschilt (Je hebt ook zoiets als een POD, komen we nog op terug)
int main(int argc, char* argv[]) { monster steve; cout << "Monster HP: " << steve.damage(12) << endl; return 0; } Output: Monster HP: 88
int main(int argc, char* argv[]) { int mCount; cin >> mCount; monster *monsters = new monster[mCount]; cout << "We now have " << mCount << " monsters. Great.." << endl; delete[] monsters; return 0; } Output: We now have monstes. Great..
Default constructors (indien aanwezig) worden automatisch aangeroepen Als er geen constructor wordt gegeven, wordt er automatisch een lege constructor aangemaakt
class A { }; int main() { A a; return 0; } class B { public: B(int foo){ } }; int main() { B b; return 0; } no default constructor exists for class "B" Compileert Compileert niet
class B { public: B(int foo){ } }; int main() { B b(0); return 0; } Compileert nu wel!
Naast een een constructor wordt ook automatisch een destructor aangemaakt Destructors worden aangeroepen als het object wordt “opgeruimt” ◦ Object gaat uit scope ◦delete wordt aangeroepen Ziet eruit als een constructor, maar begint met ~
class A { public: A() { cout << "Vanaf nu besta ik!" << endl; } ~A() { cout << "Vaarwel!!" << endl; } }; int main() { A a; return 0; } Output: Vanaf nu besta ik! Vaarwel!!
int main() { cout<< "Voor scope" << endl; { A a; } cout << "Na scope" << endl; return 0; } Output: Voor scope Vanaf nu besta ik! Vaarwel!! Na scope
int main() { A *a = new A; cout<< "Voor delete" << endl; delete a; cout << "Na delete" << endl; return 0; } Output: Vanaf nu besta ik! Voor delete Vaarwel!! Na delete
Geeft de mogelijkheid om dingen te doen net voor je object verdwijnt Waarom? Zoals je moeder altijd zei: “Voordat je met iets nieuws gaat spelen, moet je eerst je oude speelgoed opruimen!”
class belangrijkeDingenManager { private: reuzachtigeContent*rC; gigaLibrary*gL; terrabyteBijhouder*tbB; public: belangrijkeDingenManager() { rC = new reuzachtigeContent(); gL = new gigaLibrary(); tbB = new terrabyteBijhouder(); } };
int main() { belangrijkeDingenManager *bdm = new belangrijkeDingenManager(); /*... Zeer interessante code hier... */ delete bdm; return 0; }
We hebben de belangrijkeDingenManager verwijderd, maar wat gebeurt er met de reuzachtigeContent, gigaLibrary en terrabyteBijhouder ? Memory Leak!
~belangrijkeDingenManager() { if(tbB) { delete tbB; tbB = 0; } if(gL) { delete gL; gL = 0; } if(rC) { delete rC; rC = 0; }
Let op met destructors! ◦ Verwijder geen dingen die al verwijdert zijn ◦ Denk aan dependencies! Verwijder in tegengestelde volgorde ◦ Wie heeft “ownership” over een pointer? De owner moet ervoor zorgen dat delete wordt aangeroepen ◦ Zorg ervoor dat de constructor niet kan falen! Hoe herstellen we bijvoorbeld van een fout/exception in de destructor?
Gedrag van een constructor ◦ Wordt aangeroepen bij het aanmaken van een nieuwe instance ◦ Roept automatisch de constructor aan van alle members Maar dat laatse kan performance hinderen!
class D { private: A m_a; B m_b; C m_c; public: D(A a, B b, C c) { m_a = a; m_b = b; m_c = c; } };
Wat gebeurt er bij de aanroep van constructor D ◦ De constructor roept de constructors van de members aan: Construct A, Constructor B en constructor C worden uitgevoerd ◦ De body van de constructor word uitgevoerd: Inhoud van m_a, m_b en m_c wordt vervangen door de argumenten Constructor A, B en C waren in dit geval dus nutteloos!
Oplossing: Initialization Lists ◦ Met speciale syntax geven we aan hoe de members geinitializeerd moeten worden: class D { private: A m_a; B m_b; C m_c; public: D(A a, B b, C c) : m_a(a), m_b(b), m_c(c) { } };
◦ Kopieert de inhoud van het argument Constructor/Destructor wordt automatisch aangemaakt (als er geen gegeven wordt) Ook een “Copy Constructor” wordt automatisch aangemaakt A(const A &a)
Ook wordt automatisch de methode voor de = operator gegenereerd ◦ Op deze manier kunnen variabelen van het type A aan elkaar toegewezen worden ◦ Let wel op! We maken een kopie! We hebben hierna dus twee verschillende objecten Copy Constructors en de operator= kunnen voor vervelende situaties leiden met onverwachte kopiën A operator=(const A &a)
Denk eraan: in C++ is alles “pass-by-value” ◦ Als je een instance als parameter doorgeeft, wordt er automatisch met de copy constructor een kopie van gemaakt! ◦ Als je niet stilstaat bij de implicaties van het gebruik van de = opperator of de copy constructors zit je ineens onverwacht met een kopie!
C ◦ You shoot yourself in the foot. C++ ◦ You accidentally create a dozen instances of yourself and shoot them all in the foot. Providing emergency medical care is impossible since you can't tell which are bitwise copies and which are just pointing at others and saying, "That's me over there."
C++ code is in twee delen opgedeeld ◦ Header: bevat alle prototypes en type definities ◦ Source: bevat de daadwerkelijke implementatie Eerst een uitleg hoe het werkt, daarna waarom we het zo aanpakken
class monster { private: float posX,posY; int health; public: monster() { health = 100; } void setPos(float x, float y) { posX = x; posY = y; } int damage(int attackPower) { health -= attackPower; return health;} };
class monster { private: float posX,posY; int health; public: monster(); void setPos(float x, float y); int damage(int attackPower); }; monster.h
#include "monster.h“ monster::monster() { health = 100; } void monster::setPos(float x, float y) { posX = x; posY = y; } int monster::damage(int attackPower) { health -= attackPower; return health; } monster.cpp
Headers geven aan wat er is ◦ Welke variabelen ◦ Welke functies zijn er ◦ Welke classes zijn er Wat zijn de members van de class Headers bevatten dus alleen Prototypes!
Source files geven aan wat er gebeurt ◦ Implementaties van functies ◦ Implementaties van classes Source files bevatten de Implementatie!
Refereert naar headers die de beschrijving geeft van de implementatie (#include) Gebruikt de scope opperator (::) om naar de correcte members van classes te verwijzen ◦ Bijv: void monster::setPos(float x, float y)
“Heel leuk dat we nu declaratie en implementatie gescheiden hebben, maar moet dit nou echt voor elke class?”
Stappen van compilatie 1.Preprocessing 2.Compilation 3.Linking
Alle preprocessor directives worden afgehandeld ◦ Alles met # is een preprocessor directive, bijv: #include #define #ifdef ...
#include ◦ Deze statement geeft aan dat de inhoud van de aangegeven file gekopieerd moet worden in de huide file #include geeft aan dat de complete header naar de huidige file gekopieerd moet worden! Toegevoegde headers kunnen ook weer includes bevatten! Ons simpele 10 regel tellende programmatje kan ineens een programma van regels worden! Stel je nu eens voor dat naast de declaraties ook de definieties erbij hadden gezeten
Macro’s: ◦ Met #define kan een macro gemaakt worden: ◦ In de code wordt elke SAFEDELETE vervangen voor de aangegeven code ◦ Ook constantes kunnen op die manier gedefinieerd worden: #define SAFEDELETE(a) if(a) { delete(a); a=0; } #define PI
Delen van de code kunnen conditioneel ingevoegd of weggelaten worden ◦ #ifdef, #ifndef, #define #if, #endif, #else en #elif ◦ Met if else structure kunnen delen conditioneel worden weggelaten. #ifdef en #ifndef kijken naar constantes gedefineerd met #define #if, #else, etc. kijken naar een expressie De preprocessor weet niks van C++ syntax: De output kan dus onzin zijn!
Als alle preprocessor directive zijn weggewerkt blijven we met de C++ code over Deze blok code heet een ‘Translation Unit’ ◦ Translation Units zijn de basis invoer voor de daadwerkelijke compiler
De compiler vertaalt een translation unit naar machine taal in binary ◦ Het kan op dit moment voorkomen dat we nog geen definities hebben voor sommige declaraties: Dit wordt in de volgende stap opgelost ◦ Dubbele declaraties zijn geen probleem ◦ Dubbele definities zorgen voor een fout waarna compilatie stopt Output zijn object files (.o of.obj)
Verschillende object files worden gelinkt tot een executable of library ◦ Missende definities worden in deze stap uit andere object files gelinkt. Het kan zijn dat tijdens het linken we nog steeds niet alle definitions kunnen vinden -> Error! Het kan zijn dat we twee keer hetzelfde gedefinieerd vinden over twee object files -> Error!
Stel: we hebben monsters en een speler die een vector2 class gebruiken om hun positie aan te geven ◦ Het spel include monster.h en speler.h ◦ monster.h en speler.h includen vector2.h Error: 'vector2' : 'class' type redefinition
Met behulp van preprocessor directives geven we aan dat een header maar 1 keer toegevoegd mag worden: #ifndef VECTOR2_H_ #define VECTOR2_H_ class vector2 { public: float x,y; }; #endif //VECTOR2_H
Oefen met de opgaven ◦ Er mee bezig gaan is de enige manier om het echt te leren! Google alles ◦ Als je iets niet begrijpt, zoek het uit, elk detail! Het meeste leer je van zelfstandig onderzoek
Ik geef een hint...