Kursinformation. Kurslitteratur. Bonuspoäng till tentan. CD5250, Objektorienterad Programmering med C++ Daniel Flemström,

Storlek: px
Starta visningen från sidan:

Download "Kursinformation. Kurslitteratur. Bonuspoäng till tentan. CD5250, Objektorienterad Programmering med C++ Daniel Flemström, daniel.flemstrom@mdh."

Transkript

1 CD5250, Objektorienterad Programmering med C++ Daniel Flemström, Kursinformation Kurshemsida Föreläsningsinnehåll + läsanvisningar för boken + allt Föreläsningsinnehåll Kommer upp vartefter på hemsidan Laborationer 7 st Kolla Minst Labbuppgifter finns på hemsidan Samma dag Projektuppgift som föreläsningen! Bygger på labbarna Kommer upp på hemsidan Förkunskapskrav: C-kurs (godkänd) Bonuspoäng till tentan Labbar och projektet klart och redovisat före tentan = 10 % Betygshöjande på tentan. (Gäller skriftlig tentamen) Labbarna skall redovisas i tid under hela kursen!!! Kurslitteratur Rekommendation: en av följande: Jan Skansholm:C++ Direkt Stephen Prata: C++-programmering Ev sidhänvisningar kommer att vara till Skansholms bok som jag personligen gillar mest.

2 Lektionsmål Efter avslutad föreläsning bör vi begripa hur man använder: CD5250 OOP med C++ Minnesallokering Defaulta värden på argument Funktionsöverlagring Mallar (Templates) Namespaces C++ Standardbibliotek <iostream> och <fstream> String och vector Sid 1 Sid 2 Kommentar och Scope Datatyper, bool Kan allt som C kan, och mer därtill. Nya datatyper. C /* Kommentar*/ #define BUFSIZE 12 int a,b,c; a = b + c; C++ // Kommentar const int BUFSIZE=12; int a,b,c; a = b + c; C #define TRUE 1 #define FALSE 0 struct kalle int age; ; void SetAge(int val, struct kalle* s,) s->age = val; C++ bool b = true; class kalle int age; void SetAge(int val) age = val; ; Sid 3 Sid 4 Datatyper, string Förenklad stränghantering C C++ char namn[200]; string namn;... strcpy(namn, Kalle ); namn = Kalle ; int l = strlen(namn); string namn2 = namn; int l = namn.length(); Minneshantering C++ har en uppsnyggad minneshantering enstaka element arrayer C C++ malloc / free new / delete malloc / free new[] / delete[] int* i = new int[200]; delete[] i; Sid 5 Sid 6

3 Lite pekarrepetition int* parrayen = new int[6]; Faror med pekare! parrayen &parrayen *parrayen parrayen[1] Om i något läge avallokering missas minnesläcka Pekare till objekt(tex array) som inte finns längre Delete av samma objekt två ggr via olika pekare obja objb Sid 7 Sid 8 Referenser Mer Om Referenser C++ har pekare men dessutom referenser C,C++ void reset(int* a) *a = 0; void main () int b = 12; reset(&b); C++ void reset(int& a) a = 0; void main () int b = 12; reset(b); Som pekare men lättare att använda. Används mest för parameteröverföring. int mitttal = 3; int &reftillmitttal = mitttal; /* jämför med nedan:*/ int *ptillmitttal = &mitttal; reftillmitttal = 4; // vad händer? Sid 9 Sid 10 Annat sätt att se referenser int a = 7; int& b = a; int* c = &a; int d = *c; // Men vad blir detta??? Overloading C++ har funktionslagring (overloading) C C++ void printint(int a); void print(int a); 0x0FA 0x0FB 0x0FC 0x0FD a,b = 7 C =0x0FA void printfloat(float a); void print(float a); void printstring(char* a); void print(char* a); Sid 11 Sid 12

4 Overloading, exempel void move(int x, int y); void move(int angle, int length); typedef int angle; //Hjälper det? class Angle; // - - Det räcker inte att returvärdets typ eller parametrarnas namn skiljer Vad händer? Default arguments C++ kan ha defaulta värden på argument C void print(int a, char sep); print (12, b ); print (12); C++ void print(int a, char sep = b ); print (12, a ); print (12); Sid 13 Sid 14 Templates C++ har templates (mallar med typkontroll) C #define myreset(a)\ a = 0 void main () int o = 12; myreset(o); float f = 12.3; myreset(f); C++ template<typename T> void myreset(t& a) a = 0; void main () int o = 12; myreset<int>(o); float f = 12.3; myreset<float>(f); Sid 15 Vector C++ har dessutom arrayer som kan växa C C++ void main () void main () int o[200]; vector<int> o; for(int i = 0; for(int i = 0; i < 200; i++) i < 200; i++) o[i] = 3; o.push_back(3); for(int i = 0; for(int i = 0; i < 200; i++) i < 200; i++) printf( %d,o[i]); printf( %d,o[i]); Sid 16 Inline C++ har inline funktioner C #define MAX(a,b)\ ((a)>(b))?(a):(b) C++ inline int MAX(int a, int b) if (a > b) return a; else return b; Sid 17 Namespaces namespace my_namespace class dog osv my_namespace::dog using namespace my_namespace; dog namespace my_ns my_namespace; diskontinuerligt nästade Sid 18

5 Egna Namespaces För att skapa ett eget namespace att lägga klasser i använder man nyckelordet namespace Standardutseende namespace jms class Matrix returtyp metod(parametrar ); ; Egna Namespaces 3 olika sätt att komma åt klassen Matrix jms::matrix matrix; Använder uttryckligen en klass i ett specifikt namespace using namespace jms; Matrix matrix; Använder hela jms namespace (risk för kollisioner) using jms::matrix; Matrix matrix; Använder endast en delmängd av jms namespace (Matrix) Sid 19 Sid 20 iostream library II I/O mot filer #include <iostream> using namespace std; Istället för printf! void main () int mitttal; cout << Gissa ett heltal << endl; cin >> mitttal;... cerr << Nåt gick snett! << endl;... #include <fstream> using namespace std; void main () ofstream outfile( Kalle.TXT ); if (outfile) outfile << text << endl; // end main Sid 21 Sid 22 I/O mot filer Enkel felhantering - assert() #include <fstream> #include <string> using namespace std; void main () string namn; ifstream infile( Kalle.TXT ); if (infile) infile >> namn; // end main Sid 23 #include <cassert> using namespace std; inline void checkrange(int index) assert (index >= 0 && index < size); ouppfyllt villkor skrivs ut och programmet avlsutas omedelbart. Sid 24

6 Objektbaserad Programmering Varför tänka i objekt / klasser? Grundläggande om klasser och objekt (Arv får vänta) Sid 1 Sid 2 Gruppera Kod och data som hör ihop C int s_xy[100][2]; Bitmap m[30]; void Draw() for(.) drawline(s_xy[i][0], for() drawbitmap(m1 void move() C++ C++ Klassbegrepp C++ Klassbegrepp Abstrahera bort detaljer C++ Skott m_skott; Bakgrund m_bak; void Draw() m_skott.draw(); m_bak.draw(); void move() Sid 3 Sid 4 Klassbegreppet En abstraktion av något till exempel star, monster, player. Grupperar ihop data med tillhörande funktioner. Man jobbar på instanser av klasser (=objekt) CStar m_xposition m_yposition move() draw() Klassens namn Medlemsdata Medlemsfunktioner CPerson m_name m_address setname() getname() setaddress() getaddress() by value CStar m_star; int m_number; Medlemsdata by reference pekare, utbytbar, kan vara 0 referens, måste kopplas till objekt, kan ej ändras sen CStar* m_pstar; CGameBoard& m_board; int* m_pnumber; Precis som med struct i C! Sid 5 Sid 6

7 Vi väljer vilka egenskaper och vilket beteende vi vill belysa class CCar void run(); void stop(); private : bool m_running; ; class CCar public : void owner(person &p); person& owner(); private : person m_owner; ; Sid 7 Medlemsåtkomst i statiskt allokerat objekt. i dynamiskt allokerat objekt, via pekare -> CStar s1; Cstar* s2 = new CStar; s1.m_xposition = 7; s1.draw(); s2->m_xposition = 9; s2->draw(); Sid 8 En klass och dess användning i Kod Klassen i uppdelad form(1/2) UML diagram CStar m_x m_y draw() move() Main.cpp class CStar void draw() drawline(m_x. void move() m_y = m_y 1; int m_x,m_y; ; CStar s1; Cstar s2; Datorminnet draw move m_x=2 m_y=4 m_x=9 m_y=3 Kod för medlemsfunktionerna Data för s1 Data för s2 Star.h #ifndef STAR_H #define STAR_H class CStar void draw(); void move(); int m_x,m_y; ; #endif Star.cpp #include Star.h void Cstar::draw() // Kod void CStar::move() m_y += 1; ; MonsterAttack.exe Main.cpp CStar s1; Cstar s2; s1.draw(); s2.draw(); Sid 9 Sid 10 Klassen i uppdelad form (2/2) Star.h #ifndef STAR_H #define STAR_H class CStar void draw(); void move(); int m_x,m_y; ; #endif Star.lib $$ MonsterAttack.exe Main.cpp #include Star.h CStar s1; Cstar s2; s1.draw(); s2.draw(); Sid 11 Klass-scope och namnupplösning Access till klassmedlem: inuti klassdefinitionen (I.H-Filen) class xxx Public: void func()m_kalle = 7; int m_kalle; ; eller i.cpp filen: xxx::func() /* kod */ m_kalle = 7; Sid 12

8 Klass-scope och namnupplösning forts En sak med ett visst namn inuti en klass döljer saker med samma namn utanför klassen Man kan komma runt detta med scopeoperatorn, exempel: ::objektx pekar ut globalt objektx så man kommer åt det även inuti en klass med ett eget objektx Sid 13 Inline member functions För att få snabbhet trots många många anrop i OOP // Star.h class CStar void move() // kod i klassdefinition blir automatiskt inline void dothat(); ; inline void Cstar::doThat()... Sid 14 Access specifiers public snittet mot användaren private interna hjälprutiner och data som användaren inte ska komma åt Vanligen alla data, en fråga om stil protected för Arvingarna, mer om det senare Klassen Star med access specifiers Star.h Star.cpp #ifndef STAR_H #include Star.h #define STAR_H void Cstar::draw() class CStar // Kod void draw(); void CStar::move() void move(); private: m_y += 1; int m_x,m_y; ; ; #endif Main.cpp #include Star.h CStar s1; Cstar s2; s1.draw(); s2.draw(); OBS! Notera att private är det som gäller om man inte skriver något annat. Vad tror du om exemplet CStar vi tittade på tidigare? Fungerar det som det stod? Sid 15 MonsterAttack.exe Sid 16 Speciella medlemsfunktioner Konstruktor - (new, new[] ) MinKlass(xxx) destruktor - (delete, delete[] ) ~MinKlass() operatorer t.ex. bool operator==(const MinKlass&) Man kan också ha en klass inuti en funktion, local class. class List class ListNode Klass inuti klass ett listobjekt Se detta som ett funktionsnamn så blir det lättare! Men OBS! - operator skrivs ej då den anropas Sid 17 information hiding! Sid 18

9 Problemet Valve_1 Tank_1 Objektbaserad Programmering Ytterligare Ett exempel Valve_2 Mixer_1 CD5250 Sid 1 CD5250 Sid 2 /* valve.h*/ typedef struct int open; Valve; void open(valve *v); void close(valve*v); /*main.c*/ #include valve.h Valve valve_1; Valve valve_2; close(&valve_1); close(&valve_2); if (valve_1.open) Hur vi gjorde i C /* valve.c*/ #include valve.h void open(valve *v) v->open = TRUE; void close(valve *v) v->open = FALSE; CD5250 Sid 3 Hur vi gör i C++? /* cvalve.h*/ /* cvalve.cpp*/ class CValve #include cvalve.h bool m_open; void open(); void CValve::open() void close(); ; m_open = true; /*main.cpp*/ #include cvalve.h void CValve::close() CValve v1; CValve v2; m_open = false; v1.close(); v2.close(); if (v2.m_open)... CD5250 Sid 4 Information Hiding /* cvalve.h*/ /*main.c*/ class CValve #include cvalve.h private: bool m_open; CValve v1; CValve v2; void open(); v1.close(); void close(); v2.close(); ; if (v1.m_open)... CD5250 Sid 5 Startvärden (1)? Konstruktor Samma namn som klassen Ingen returtyp /* cppvalve.h*/ class CValve private: int m_open; CValve(); // Konstruktor! void open(valve *v); void close(valve*v); ; CD5250 Sid 6

10 Konstruktor Startvärden (2)? /* cvalve.cpp*/ #include cvalve.h CValve::CValve() m_open = false; void CValve::open() m_open = true; void CValve::close() m_open = false; objekt klass instans public / private konstruktor Sammanfattning CD5250 Sid 7 CD5250 Sid 8

11 Lektionsmål Efter avslutad föreläsning bör vi : Objektbaserad Programmering Första Duvningen Kunna se omvärlden som objekt Implementera klasser för objekt. Förklara Klass, Objekt, Instans CD5250 Sid 1 CD5250 Sid 2 Problemet KATT Klösa Riva Bita bli arg bli snäll antalklor arg? CD5250 Sid 3 Hur vi gjorde i C /* cat.h*/ /* /* cat.c*/ typedef struct #include cat.h int angry; void beangry(cat *v) Cat; void beangry(cat*v); v->angry void benice(cat*v); = TRUE;... /*main.c*/ void benice(cat *v) Cat c; v->angry = FALSE; beangry(&c); if (c.angry)... CD5250 Sid 4 Hur vi gör i C++(1) /* CCat.h*/ /* CCat.cpp*/ class CCat #include CCat.h bool m_angry; void CCat:: beangry() void beangry(); void benice(); m_angry = true; ; void CCat::beNice() /*main.cpp*/ m_angry = false; Cat catbert; catbert. beangry(); if (catbert.m_angry)...? CD5250 Sid 5 Information Hiding /* CCat.h*/ /*main.c*/ class CCat #include ccat.h Private: bool m_angry; Cat catbert; catbert.benice(); Public: if (catbert.m_angry) void beangry(); void benice(); ; CD5250 Sid 6

12 Startvärden (1)? Konstruktor Samma namn som klassen Ingen returtyp /* CCat.h*/ class CCat Private: bool m_angry; Public: CCat(); // Konstruktor! void beangry(); void benice(); ; CD5250 Sid 7 Startvärden (2) Konstruktor( implementation) /* ccat.cpp*/ /*main.c*/ #include ccat.h #include ccat.h CCat::CCat() Cat garfield; m_angry = true; //Är han snäll nu? void CCat:: beangry() m_angry = true; void CCat::beNice() m_angry = false; CD5250 Sid 8 Sammanfattning objekt klass instans public / private konstruktor CD5250 Sid 9

13 /* radio.h*/ typedef struct int kanal; Radio; Medlemsåtkomst i C /*main.c*/ #include radio.h Radio r1; Radio r1; r1.kanal = 12; if (r2.kanal == 4) CD5250 Sid 1 Hur vi gör i C++? /* radio.h*/ /* cvalve.cpp*/ class Radio #include cvalve.h Private: int m_kanal; int Radio::getKanal() Public: int getkanal(); return m_kanal; void setkanal(int k); ; /*main.cpp*/ void #include Radio.h Radio::setKanal(int k) m_kanal = k; Radio r1,r2; r1.setkanal(12); int i = r2.getkanal(); CD5250 Sid 2

14 UML diagram CStar m_x m_y m_size draw() move() Klassvariabler Main.cpp class CStar void draw() drawline(m_x. void move() m_y = m_y 1; int m_x,m_y; static int m_sizet; ; CStar s1; Cstar s2; Datorminnet draw move m_size m_x=2 m_y=4 m_size m_x=9 m_y=3 m_size Kod för medlemsfunktionerna Data för s1 Data för s2 Sid 1 Klassvariabler (uppdelad form) Star.h Star.cpp Main.cpp #ifndef STAR_H #include Star.h #define STAR_H void Cstar::draw() class CStar // Kod CStar::m_size = 7; CStar void draw(); s1; Cstar void move(); void CStar::move() s2; int m_x,m_y; s1.m_size = 8; static int m_size; m_y += 1; s1.draw(); ; s2.draw(); int CStar::m_size = 7; #endif Dock är m_size private så detta funkar inte att kompilera. MonsterAttack.exe Sid 2 UML diagram CStar m_x m_y m_size draw() move() setsize() Klassmetod och dess anrop. Datorminnet Main.cpp class CStar draw // Som förut move static void setsize(int s) m_size = s m_size=10 int m_x,m_y; m_x=2 static int m_sizet; ; m_y=4 m_size CStar::setSize(10); CStar s1; m_x=9 Cstar s2; m_y=3 m_size Sid 3 Kod för medlemsfunktionerna Data för s1 Data för s2 Klassmetod(uppdelad form) Star.h #ifndef STAR_H #define STAR_H class CStar void draw(); void move(); static void setsize(int s); int m_x,m_y; static int m_size; ; #endif Star.cpp #include Star.h // som förut void CStar::setSize(int s) m_size = s; Main.cpp // Som förut. MonsterAttack.exe Sid 4 Klassvariabler, Exempel klass objekt (mittsparkonto) objekt (dittsparkonto) SparKonto klass SparKonto Klassmetoder static raenta 8% behallning static raenta behallning 800 static raenta behallning 850 kan användas även om inga objekt finns kan döljas i klassen med private, säkrare än globala objekt initerasi klassnamn.cpp static const int kan initieras i klassdefinition Sid 5 aendraraenta(nyraenta) static raenta 8% behallning används för att manipulera klassdata kan användas även om inga objekt finns (kompileringsfel om man försöker manipulera objektdata) Sid 6

15 Att tolka konstantdeklarationer float pi; const float pi = ; float *pip = π //Kompileringsfel! Utan #define! const float *pip = π //pekare till konstant objekt //(får även peka på icke-konstant objekt som då ej kan //ändras via pekaren) char *const buffer = &buf; // Konstant pekare, pekar // alltid på samma buffert. const char * const myprog = argv[0]; //Konstant pekare till konstant objekt CD5250 Sid 1 Konstanta objekt(1) const CMinKlass mittobj; får inte förändras när de väl skapats. mittobj.aendra(); // Ändringsförsök?? Hur håller kompilatorn / programmeraren reda på vad medlemsfunktionerna gör? CD5250 Sid 2 Konstanta objekt(2) Konstanta medlemsfunktioner // minklass.h class CMinKlass void aendra() m_data = 12; private: int m_data; ; const CMinKlass a; a.aendra(); // F E L. class CMinKlass void aendra(); void kolla() const; private: int m_data; ; // minklass.cpp CMinKlass::kolla() const // Kompileringsfel om // man försöker ändra I // klassdata! m_data = 12; // F E L! CD5250 Sid 3 CD5250 Sid 4 Att ändra iallafall(1) Att ändra iallafall // minklass.h class CMinKlass void aendra(); void kolla() const; Undvik att Ändra!!!! // minklass2.h class CMinKlass2 void aendra(); void kolla() const; private: char* m_data; ; private: mutable int m_data; ; Försök designa bort! CD5250 Sid 5 CD5250 Sid 6

16 Identifiera och klassificera objekt MonsterAttack Monster Type1 MonsterAttackGame Monster Type2 Repetition av klasser och OOP Fördjupning i relationer Star ShipBullet Ship Gör Klassdiagram(kap 6.2) Klasser ShipBullet x y caliber moveto(x,y) setcaliber() Namn Egenskaper Operationer (Metoder) class namn deklarationer av synliga medlemsfunktioner och datamedlemmar private: deklarationer av gömda medlemsfunktioner och datamedlemmar ; UML = unified modeling language. Tillgänglighet (kap. 7.1) Utanför klassen kommer man bara åt synliga medlemmar (public) Utifrån används punkt eller pil för åtkomst av medlemmar (public) Objektnamn.medlemsnamn Pekare_till_objekt -> medlemsnamn Inne i en medlemsfunktion kan man komma åt alla medlemmar utan punktnotation this-pekaren (kap. 8.2) I alla metoder finns en dold pekare som heter this this pekar ut det objekt som metoden arbetar på Via this -pekaren kommer man åt datamedlemmar Kompilatorn sköter normalt detta åt oss

17 void Size::SetX(int x) m_x = x; void Size::SetX(int x) this->m_x = x; this forts. Dessa två metoder är ekvivalenta Kompilatorn förstår oftast när this-pekaren skall användas, därför behöver man oftast inte använda thispekaren. this forts. Metoder kan returnera this-objektet Kan användas för att länka ihop metodanrop Klass & Klass::metodnamn(parametrar) return *this; Klass objekt; objekt.metod1().metod2().metod3(); Medlemsfunktioner (kap. 7.2) Bör definieras separat, utanför klassdefinitionen (i cpp-filen) resultattyp klassnamn::funktionsnamn(parametrar) Kan även definieras i klassen om funktionen är väldigt kort (motsvarar inline) #ifndef KLASSNAMN_H #define KLASSNAMN_H h-filen class Klassnamn Klassnamn(); // Defaultkonstruktor Klassnamn(int p, int q); void Funktionsnamn(int p); ; #endif // KLASSNAMN_H cpp-filen Relationer Mellan Objekt 1 knows MonsterGame 1 0..n MonsterType1 #include Klassnamn.h Klassnamn::Klassnamn() Klassnamn::Klassnamn(int p, int q) void Klassnamn::Funktionsnamn(int p) 4 Bitmap 0..n [MonsterType2] 1 Ship Bitmap Bullets 0..n ScorePanel Har, Känner till, Är Bullet

18 Har(består av)-relation Komposition (eng Composition) Grafisk beskrivning av hur objekt är kopplade till varandra (har-relation) MonsterGame består (bla) av en ScorePanel Ägaren ansvarar för konstruktion / destruktion Har (består av)-relation forts. Sammansättning av flera delobjekt Bil MonsterGame ScorePanel Motor Hjul Kaross Har Relation i KOD #ifndef MONSTERGAME_H #define MONSTERGAME_H class MonsterGame private: Har - association Aggregat (UML) Ungefär samma som komposition, men Ägaren ansvarar inte för konstruktion / destruktion ScorePanel m_score; // skapas / förstörs automatiskt ScorePanel * m_pscore; // Kräver konstruktor och // destruktor ; Respektive leverantör ansvarar för sina varuställ SuperMarket #endif // MONSTERGAME_H MonsterGame skapar och förstör objektet m_score och det m_pscore pekar på. Mjölk Bröd Läsk Andra Associationer Tex, Känner till objekt men äger dem inte (på samma sätt som vid komposition). Gör något med något annat objekt Noll eller flera grodor känner till noll eller en Jägare 0..* 0..1 Groda Jägare En jägare skjuter ingen eller max 3 grodor Skjuter 1 Groda Jägare Multiplicitet Relation kan vara: 1-1,1-M, M-1, M-M M=Många (Many) Om objektet i ena ändan ibland saknas: Pil kan ange riktning (kan även vara dubbelriktad) Obs! Pil kan även ange arv - pekar på föräldern

19 Känner till Relation i Kod Fler Exempel #ifndef KLASSNAMN_H #define KLASSNAMN_H class Hunter private: Frog* m_pfrog; ; #endif // KLASSNAMN_H Hunter varken skapar eller förstör objektet m_pfrog pekar på. Gevär x y kaliber moveto(x,y) setcaliber() Jägare x y moveto(x,y) Skjut() Groda x y moveto(x,y) Skjut()

20 Konstruktorn forts. Konstruktion och destruktion Har samma namn som klassen Ser ut som en metoddeklaration förutom att den inte har ett returvärde Size(int width, int height)... Undviker följande scenario Size s; s.create(10,5); Destruktorn (kap. 7.4) metod som anropas automatiskt när objektet tas bort Används för att städa upp efter ett objekt Avallokera minne Släppa resurser Har inga parametrar Har samma namn som klassen fast med ett ~ framför class Skott Exempel Skott(int x, int y); ~Skott(); private: int m_x; int m_y; ; Exempel (forts.) // Konstruktor (cpp filen) Skott::Skott(int x, int y) m_x = x; m_y = y; Övning Skriv ned klassen Hunter som dynamiskt skapar sig ett vapen (GUN) // Destruktor Skott::~Skott() // Avallokera eventuellt minne m.m.

21 Övning, Lösningsförslag // Konstruktor Hunter::Hunter() m_pgun = new Gun; // Destruktor Hunter::~Hunter() delete m_pgun; Kopieringskonstruktor (kap ) Det finns en speciell konstruktor som kopierar hela objekt av samma typ Size s1(10,5); Size s2(s1); // s1 kopieras till s2 Size s2=s1; // s1 kopieras till s2 // Defaultimplementation Skott::Skott(const Skott & s) m_x = s.m_x; m_y = s.m_y; Kopieringskonstruktor forts. Konstruktorn finns alltid i C++ Default-beteende: kopiera alla datamedlemmar element för element. Kopieringskonstruktorn för datamedlemmar används vid elementvis kopiering Överlagra konstruktorn då speciell behandling krävs Ex. om minne skall allokeras för varje enskilt objekt, annars kopieras minnespekarens värde! Kopieringskonstruktor forts. Kopieringskonstruktorn används Då nyskapat objekt tilldelas ett objekt // Kopieringskonstruktor anropas Point p2 = p1; // Kopieringskonstruktor används inte p2 = p1; Då objekt skickas som parametrar Då objekt returneras från metoder Gör du en kopieringskonstruktor skall du också överlagra = operatorn Typomvandlingskonstruktor (kap ) Konstruktor med EN parameter eventuellt fler, om de har defaultvärden Gör följande uttryck möjliga string s = implicit typkonvertering ; // Typkonverteringskonstruktor string s = sträng ; // Resulterar i string s = string( sträng ); Typomvandlingskonstruktor forts. Kan medföra problem Implicit konvertering kan ske utan programmerarens avsikt Använd explicit framför konstruktorer som har en parameter och som inte skall fungera som automatisk typomvandlingskonstruktor explicit Text(int n); Nu måste man skriva mytext = Text(12)

22 Övning Lägg till kopieringskonstruktor i Hunter Är det lämpligt att ha en Typomvandlingskonstruktor? Initieringslistor (kap ) Hur skall medlemsobjekt vars konstruktor tar argument initieras? Exempel: Size Initieringslistan har formen: : d1(uttryck), d2(uttryck) Klassnamn::Klassnamn(int width, int height) : m_size(width,height) Initieringslistor forts. Referenser kan bara initieras när de deklareras Hur skall referenser i klasser initieras? Member initializer list i konstruktorn Klassnamn::Klassnamn(Objekt & o): m_referens(o) Initieringslistan, exempel Använd detta! God stil, förhindrar fel och dubbelarbete! _length: 3 _name: olle initieringsordning! class CMinKlass int m_length; string m_name; CMinKlass::CMinKlass(int length; const string& name) : m_name(name), m_length(length)/*kod*/ I vilken ordning kommer dessa två satser att exekveras? Vad säger linux kompilator?

23 Operatoröverlagring (kap. 8.4) Operatoröverlagring Funktioner eller metoder som anropas genom aritmetiska tecken istället för metodnamn Namn börjar med operatorx X ersätts med +, -, =,!=, >, <, >>, << m.fl. Kan snygga upp programkoden Ökar dock inte språkets uttrycksmöjligheter Syntaktiskt socker Operatorer Binära operatorer Kan ha en operand (unära) eller två operander (binära) Operatorerna har samma prioritet som motsvarande fördefinierade operatorer Kan konstrueras som medlemsfunktioner eller vänfunktioner Har två operander Vänster operand är av klassens typ: Den vänstra är objektet själv (this) Den högra fås som argument Vänster operand är av en annan typ: Vanlig funktion som tar två argument. Måste ofta friend-deklareras i klassen, Exempel: ==,!=, +=, -=, +, - Olle a,b,c a = b + c a = 5 + c Exempel (binär operator) Vad sker? Size Size::operator+(Size const & s) const // this är första operand, s andra Size temp = *this; //skapa temporär kopia! temp += s; // använd += operatorn return temp; // returnera temporärt objekt Size s(10,10); Size t(5,5); Size u = s+t; // s+t skapar ett temporärt objekt // s är första operand, t andra // Detta är därför fullt möjligt int w = (s+t).width(); // ger w = 15 objc = obja + objb; 1. ObjA får i uppdrag att utföra additionen. 2. ObjA skapar ett temporärt objekt och lägger resultatet i det. 3. ObjC får i uppdrag att byta sitt värde mot temporärobjektets. 4. Temporärobjektet försvinner. 5. Resultatet av hela satsen är objc.

24 Tilldelningsoperatorn Size& Size::operator=(Size const & s) if(&s!= this) m_width = s.m_width; m_height = s.m_height; return *this; Size s1; Size s2; s1 = s2; // Tilldelningsoperatorn används Tilldelningsop. forts. if(&s!= this) Kopiera aldrig dig själv return *this; Returnera objektet själv som resultat av tilldelningen // OBS skillnaden mot tilldelningskonstruktorn // Tilldelningsoperatorn används inte här Size s3 = s1; Operatorn += Liknar tilldelningsoperatorn i användningsätt Size& Size::operator+=(Size const & s) m_width += s.m_width; m_height += s.m_height; return *this; Size s1(10,5); Size s2(2,2); s1 += s2; // += operatorn används // s1 skall nu vara (12,7) Unära operatorer Har en operand Tar oftast inga parametrar Exempel: ++, --, - Size Size::operator-() const Size temp; temp.m_width = -m_width; temp.m_height = -m_height; return temp; Indexeringsoperatorn operator[] Används för indexering i t.ex. std::vector Standardbeteende är att lämna tillbaks en referens till ett element, så kan man både läsa och skriva till det indexerade elementet Indexeringsoperatorn forts. Skapa också en const -variant av de metoder som returnerar referenser till objekt int& Vektor::operator[](int index) return element; int& Vektor::operator[](int index) const return element;

25 Övriga operatorer operator()(); Funktionsanropsoperator Valfritt antal parametrar operator typ() const; Inga parametrar eller returvärde anges Omvandlar från den aktuella klassen till typen typ Anropas automatiskt när typomvandling behövs friend-operatorer Operatorer som inte passar i klasser Måste användas när vänsteroperanden inte tillhör den aktuella klassen Har lika många parametrar som antal operander friend returtyp operatorx(parametrar); friend-operatorer forts. // friend-funktion ostream & operator<<(ostream & o, Size const& s) o << s.m_width <<, << s.m_height; return o; // Tillägg i Size-klassen friend ostream & operator<<(ostream & o, Size const& s); Size s(10,4); // skriv ut s har storleken 10,4. cout << s har storleken << s <<. << endl;

26 Lektionsmål Efter avslutad föreläsning bör vi : Objektorienterad Programmering Arv Kunna se omvärlden som objekt Gruppera ihop gemensamma data / funktioner till överklasser. Finna lämpliga arvshiearkier på ett givet problem. Skydda data och metoder CD5250 Sid 1 CD5250 Sid 2 Arv bakgrund Problemet Hund Katt Många klasser delar på egenskaper och beteende Det framstår onödigt att återskapa samma saker om och om igen C++ erbjuder verktyg för att samla ihop gemensamma egenskaper och beteenden i överklasser pälsfärg favoritben smutsa ned() ät katt() Kanin pälsfärg slaktvikt smutsa ned() pälsfärg smutsa ned() klössoffa() CD5250 Sid 3 CD5250 Sid 4 Problemlösningsmetodik Lösningen Husdjur Oftast börjar man med att hitta de objekt man behöver - och deras klasser Sen letar man rätt på beteende som är gemensamt för flera klasser bryts ut till överklass Man tittar också efter existerande klasser man kan använda Hund favoritben ät katt() pälsfärg smutsa ned() Kanin slaktvikt Katt klössoffa() CD5250 Sid 5 CD5250 Sid 6

27 Arv innebär Arv innebär forts Underklassen är en utökad variant av överklassen Underklassen klarar minst allt vad överklassen klarar, oftast mer Underklassen innehåller garanterat all den data som finns i överklassen, dessutom kan extra data finnas Underklassens beteende är mer specialiserat Överklassens beteende är mer generellt Klasser som är mycket generaliserade har vi ingen nytta av att instansiera - abstrakta överklasser CD5250 Sid 7 CD5250 Sid 8 Vad ärvs? C++, Överklassen Husdjur medlemsfunktioner ärvs medlemsdata ärvs friends (vänner) ärvs inte konstruktor ärvs inte basklassens konstruktor anropas, vanligen från initieringslistan för att sätta rätt värden i basklassdelen en nivå upp kan man anropa Hund Husdjur Kanin Katt /* husdjur.h*/ class Husdjur void smutsa_ned(); protected: CFärg m_pälsfärg; ; CD5250 Sid 9 CD5250 Sid 10 Syntax för Hunden Syntax för Kaninen Hund Husdjur Kanin Katt /* Hund.h*/ class Hund:public Husdjur void ät_katt(); protected: CBone m_favoritben; ; Hund Husdjur Kanin Katt /* Kanin.h*/ class Kanin:public Husdjur private: double m_slaktvikt; ; CD5250 Sid 11 CD5250 Sid 12

28 Husdjur Syntax för katten /* Katt.h*/ class katt:public Husdjur Public: void klössoffa(); ; Ännu ett exempel:fordon class Fordon Fordon(Person & owner); Point GetPosition() return m_position; Person & GetOwner() return m_owner; protected: Point m_position; Person & m_owner; ; Hund Kanin Katt // Fordon initierar owner & position i sin // initieringslista Fordon::Fordon(Person & owner) : m_position(10,5), m_owner(owner) CD5250 Sid 13 CD5250 Sid 14 Bil ärver från Fordon Alltså är en Bil ett Fordon // Ärver från Fordon class Bil : public Fordon Bil(Person & owner); void TurnWheel(float wheel); protected: float m_wheelpos; // vi kommer åt alla Fordons medlemsvariabler void Bil::TurnWheel(float wheel) m_wheelpos = wheel; int x = GetPosition().GetX(); // Bilkonstruktorn anropar överklassens konstr. // OBS likheten med initieringslista av variabler Bil::Bil(Person & owner) : Fordon(owner) m_wheelpos = 0; // vi kan använda m_owner som är deklarerad // i klassen Fordon cout << Bilen med ägare << m_owner.name() << svänger med ratten << endl; CD5250 Sid 15 CD5250 Sid 16 Motorcykel ärver från Fordon // Ärver från Fordon class Motorcykel : public Fordon Motorcykel(Person & owner); void SetColor(int color) m_color = color; int GetColor() return m_color; protected: int m_color; // Konstruktorn anropar överklassens Fordon. Motorcykel::Motorcykel(Person & owner) : Fordon(owner) m_color = 0; CD5250 Sid 17 Gemensamt mellan Motorcykel och Bil Motorcykel och bil har endast Fordon gemensamt Inga andra egenskaper delas mellan objekten Klasser byggs upp i trädstruktur Underklasser är mer specialiserade Underklasserna erbjuder samma gränssnitt som överklasserna CD5250 Sid 18

29 Metodersättning En underklass kan ersätta en metod i överklassen genom att definiera om den i underklassen Överklassens ursprungliga metod kan anropas från underklassen med operatorn :: Exempel: Fordon::GetPosition() Public inheritance - synligt arv public (synliga) members i överklassen blir public underklassen Protected (skyddade) members i överklassen blir protected i underklassen (privata medlemmar i överklassen kommer man inte åt alls från underklassen) CD5250 Sid 19 CD5250 Sid 20 Protected inheritance - skyddat arv public members i överklassen blir protected i underklassen protected members i överklassen blir protected i underklassen (privata medlemmar i överklassen kommer man inte åt alls från underklassen) Private inheritance - privat arv public members i överklassen blir private i underklassen protected members i överklassen blir private i underklassen (privata medlemmar i överklassen kommer man inte åt alls från underklassen) CD5250 Sid 21 CD5250 Sid 22 Exempel (tillgänglighet vid arv) Privat eller skyddat arv class Stack : private vector<elem> // main Stack s; void push(elem e) Elem e,e1,e2; /* peta i vektorn */ Elem pop() s.push(e1); /* peta i vektorn */ s.push(e2); ; e = s.pop(); Vad händer om man använder public inheritance istället? CD5250 Sid 23 Vi får ett väldigt fult anropssnitt! t=teststack[10]; teststack.push_back(e); en stack är inte en vektor Snyggare och bättre med en vektor som beståndsdel (aggregat) istället för arv class Stack push(elem e) thestack.pushback(e); Elem pop() /* */ private: vector<elem> thestack; ; CD5250 Sid 24

30 Översikt i överklass typ av arv i underklass public public public protected public protected private public ej åtkomlig public protected protected protected protected protected private protected ej åtkomlig public private private protected private private private private ej åtkomlig Fordon Person & ägare Point position Minneslayout Nya datamedlemmar läggs till i slutet av klassen, ärvda medlemmar ligger alltid på samma offset i minnet Bil Person & ägare Point position float wheelpos Motorcykel Person & ägare Point position int color CD5250 Sid 25 CD5250 Sid 26 Ett statiskt allokerat objekt Slicingexempel Ett statiskt allokerat objekt har en bestämd storlek reserverat i minnet Ett underklass-objekt kräver mer lagringsutrymme än överklassobjekten för att få rum med de extra datamedlemmarna Slicing uppstår om ett objekt av en överklass tilldelas ett objekt av en underklass! All data i underklassen får inte rum, och förkastas därför Undvik genom att använda pekare eller referenser // main.cpp Katt k; Husdjur h = k; // S LI CI NG Husdjur* ph = &k; // OK! CD5250 Sid 27 CD5250 Sid 28 Konstruktor-destruktor vid arv När ett objekt skapas sker följande: 1. Konstruktorn för ev. överklass anropas alltid först. Genom att använda initieringslistan kan man välja vilken! 2. Konstruktorerna för den aktuella klassens datamedlemmar anropas Genom att använda initieringslistan kan man välja dessa! 3. Satserna i den aktuella klassens konstruktor exekveras. När ett objekt tas bort sker följande: 1. Satserna i den aktuella klassens destruktor exekveras. 2. Destruktorerna för den aktuella klassens datamedlemmar anropas 3. Destruktorn för ev. överklass anropas. CD5250 Sid 29

31 Lektionsmål Efter avslutad föreläsning bör vi kunna : Objektorienterad Programmering Polymorfism Förklara begreppet virtual. Implementera polymorfism CD5250 Sid 1 CD5250 Sid 2 Problemet Virtuell metod innebär Husdjur Hund favoritben ät katt() pälsfärg smutsa ned() Kanin slaktvikt Katt klössoffa() Överklassen kan implementera ett default beteende I virtuella metoder. Underklasser kan överrida såna metoder. Om dom vill. Man kan tvinga underklassen att implementera medoder (pure virtual) CD5250 Sid 3 CD5250 Sid 4 Överklassen Husdjur Syntax för Kaninen /* husdjur.h*/ class CHusdjur virtual void smutsa_ned() // Släpp hår överallt protected: CFärg m_pälsfärg; ; /* Kanin.h*/ class CKanin:public CHusdjur protected: double m_slaktvikt; ; CD5250 Sid 5 CD5250 Sid 6

32 Syntax för Hunden /* Hund.h*/ class CHund:public CHusdjur void ät_katt(); virtual void smutsa_ned() // Bit istället sönder saker, och kräks // på den dyraste mattan protected: CBone m_favoritben; ; Syntax för katten? /* Katt.h*/ class CKatt:public CHusdjur void klössoffa(); virtual void smutsa_ned() // Släpa in halvdöda möss // Gör dessutom som alla andra CHusdjur::smutsa_ned(); protected: ; CD5250 Sid 7 CD5250 Sid 8 Exempel på användning Pure virtual function /* main.cpp*/ CDjurlista l; CHund* polga = new CHund; CKatt* pbettan = new CKatt; l.add(polga); l.add(pbettan); l.smutsa_ned(); Definierar (en del av) ett snitt utan att implementera det class IDrawable virtual void draw() = 0; virtual void draw3d() = 0; CD5250 Sid 9 = 0 markerar pure virtual function CD5250 Sid 10 Anrop av virtuella funktioner II // main.cpp CKatt* pk = new CKatt; pk->smutsa_ned( ); Problemet Husdjur pälsfärg smutsa ned() CHusdjur* ph = pk; ph->smutsa_ned( ); Vilken variant körs? Hund favoritben ät katt() Kanin slaktvikt Katt klössoffa() CD5250 Sid 11 CD5250 Sid 12

33 Abstrakt överklass Rent abstrakt överklass Klass som innehåller en/flera rent virtuella metoder Klasser med rent virtuella metoder kan ej instansieras Exempel: Husdjur, hur skulle detta objekt se ut? Underklass måste komplettera klassen för att kunna instansieras Referenser/pekare till objekt av överklassen kan ändå anropa de rent virtuella metoderna Alla medlemmar är rent virtuella (pure virtual) Definierar ett gränssnitt som arvtagare måste implementera (för att kunna instansieras) CD5250 Sid 13 CD5250 Sid 14 Interface-klasser Virtuella destruktorer Klasser utan datamedlemmar Mestadels rent virtuella metoder Kan ha enklare virtuella metoder med implementation Undviker problem vid multipelt arv eftersom ingen data kan dubbleras Ärv maximalt en klass med implementation, resten Interface-klasser Namnkollisionsproblematiken kvarstår dock När man använder virtuella metoder i en klass bör man ta som vana att även deklarera destruktorn virtuell. Om man misstänker att klassen skall användas polymorft bör man även skapa en virtuell destruktor Att inte skapa en virtuell destruktor kan i vissa fall få förödande konsekvenser CD5250 Sid 15 CD5250 Sid 16 Sammanfattning Sammanfattning forts. Polymorf metod (polymorfism) metod med många former Egenskapen att kunna ha flera olika beteenden beroende på objekt Ersättning av metoder i underklasser Statisk bindning Kompilatorn bestämmer vid kompileringstillfället vilken metod som skall anropas CD5250 Sid 17 Dynamisk bindning Programmet avgör vilken metod som skall anropas först när programmet kör (run-time) Åstadkoms i C++ genom virtual Inte lika effektivt som statisk bindning, men inte så allvarligt på dagens processorer CD5250 Sid 18

34 Konvertering subtyp supertyp Konverteringar Ytterligare ett led i den allmänna förvirringen Husdjur pälsfärg smutsa ned() Hund favoritben ät katt() Konvertering från subtyp till supertyp är tillåtet - sker automatiskt (implicit) vid behov! Nödvändigt för att OOP ska fungera. (Glöm inte: pekare/referenser, annars slicing) Upcast CD5250 Sid 1 CD5250 Sid 2 Konvertering subtyp supertyp Up / Down cast exempel Husdjur pälsfärg smutsa ned() Hund favoritben ät katt() Konvertering från supertyp till subtyp görs med dynamic_cast För att komma åt medlem som bara finns i subtypen. Är det dålig design att ha sådana medlemmar? Downcast Husdjur pälsfärg smutsa ned() /* main.cpp*/ CHund* olga = new CHund; CHusdjur* p = olga; Up Down CHund* pvalp; pvalp = dynamic_cast<chund*>(p); if(!pvalp) Hund favoritben return e_nodog; p->smutsa_ned(); // vilken? ät katt() p->ät_katt(); // NEJ! CD5250 Sid 3 CD5250 Sid 4 dynamic_cast med pekare void changedirection(drawable *pobj) Pil *pp = dynamic_cast<pil*>(pobj); if (pp) // Det var en pil, konvertering lyckades! pp->byt_riktning(); Objektets dynamiska typ är känd men för medlemsåtkomst används den statiska typen. dynamic_cast med referens Drawable &pobj = hamtanastaobj(); try Pil& pp = dynamic_cast<pil&>(pobj); pp->byt_riktning(); catch (std::bad_cast) /* Det var inte en pil */ CD5250 Sid 5 CD5250 Sid 6

35 typeid och type_info #include <typeinfo> type_info ti; class Minklass : public Overklass ; Minklass mittobj; Overklass *minpekare = & mittobj; ti = typeid(*myptr); cout << ti.name() << endl; // Vad händer? :-( För avlusning, anses fult att använda i färdiga program typeid och type_info forts cout << ti << endl; // Vad händer? klass med virtuella funktioner: det av myptr utpekade objektets dynamiska typ skrivs ut, dvs Minklass klass utan virtuella funktioner: den statiska typen hos uttrycket (*myptr) skrivs ut, dvs Basklass typeid funkar på alla slags typer och uttryck: typeinfo(myint), typeinfo(a b), typeinfo(3.14) :-( CD5250 Sid 7 CD5250 Sid 8

36 Multipelt arv (kap. 9.10) Klasser kan ärva från mer än en klass För varje klass specificeras om arvet är public, protected eller private Används för att kombinera egenskaper från två eller flera klasser Exempel (multipelt arv) Amfibiebil ärver alla egenskaper som bil och båt har En Amfibiebil är en Bil och en Båt Bil Båt Amfibiebil Sid 1 Sid 2 Namnkonflikter När klasser ärver från flera överklasser kan namnkonflikter uppstå Exempel: om både bil och båt har implementerat två metoder som heter Print Namnkonflikterna löses genom att ersätta metoden Print i underklassen och specificera vilken metod i överklassen som skall anropas. Detta löses med exempelvis Bil::Print. Eventuellt kan bägge överklassernas metoder anropas efter varandra Exempel (Amfibiebil) class Bil Bil(int age) m_age = age; void Print() cout << Bil, årsmodell << m_model; protected: int m_model; ; class Bat Bat(int length) m_length = length; void Print() cout << Båt, längd << m_length; protected: int m_length; ; Sid 3 Sid 4 Exempel (Amfibiebil) forts. Exempel (multipelt arv) class Amfibiebil : public Bil, public Bat Amfibiebil(int age, int length) : Bil(age), Bat(length) // för att undvika namnkonflikter måste vi // ersätta metoden Print void Print() // skriv först ut bilinformationen Bil::Print(); // sedan båtinformationen Bat::Print(); ; Bil Fordon Amfibiebil Båt Sid 5 Sid 6

37 Konstigheter med multipelt arv Virtuellt arv Fordon Multipelt arv kan medföra problem i vissa fall Om en klass ärver från två klasser som har en gemensam överklass får underklassen dubblerade data från den gemensamma överklassen Namnkonflikter uppstår för metoder från den gemensamma överklassen Undvik multipelt arv (ATL- Det stora undantaget) När man ärver multipelt från två eller fler klasser med gemensamma överklasser uppstår datadubblering För att undvika detta kan man ärva klasser virtuellt, vilket gör att alla klasser i arvshierarkin endast finns med i en uppsättning Bil Amfibiebil Båt Sid 7 Sid 8 Exempel (virtuellt arv) class Fordon Fordon(Person & owner); Point GetPosition() return m_position; Person & GetOwner() return m_owner; protected: Point m_position; Person & m_owner; ; Exempel (virtuellt arv) class Bil : public virtual Fordon Bil(int age) m_age = age; void Print() cout << Bil, årsmodell << m_model; protected: int m_model; ; class Bat : public virtual Fordon Bat(int length) m_length = length; void Print() cout << Båt, längd << m_length; protected: int m_length; ; Sid 9 Sid 10 Exempel (multipelt arv) Klassen ärver multipelt precis som tidigare (får nu en uppsättning fordonsegenskaper) class Amfibiebil : public Bil, public Bat Amfibiebil(int age, int length) : Bil(age), Bat(length) // för att undvika namnkonflikter måste vi // ersätta metoden Print void Print() Bil::Print(); Bat::Print(); ; Sid 11 Sammanfattning virtuellt arv Virtuellt arv måste specificeras redan på den nivån i klasshierarkin där de ärver från samma klass. Dubblering av data kan undvikas genom att ärva virtual Varje datamedlemsaccess sker virtuellt Prestandaförsämring, värre än virtuella funktioner Sid 12

38 multipelt Interface-klasser Konstruktor-destruktor och arv Klasser utan datamedlemmar Mestadels rent virtuella metoder Kan ha enklare virtuella metoder med implementation Undviker problem vid multipelt arv eftersom ingen data kan dubbleras Ärv maximalt en klass med implementation, resten Interface-klasser Namnkollisionsproblematiken kvarstår dock När ett objekt skapas sker följande: 1. Konstruktorn för ev. överklass anropas alltid först. i deriveringslistans turordning 2. Konstruktorerna för den aktuella klassens datamedlemmar anropas 3. Satserna i den aktuella klassens konstruktor exekveras. När ett objekt tas bort sker följande: 1. Satserna i den aktuella klassens destruktor exekveras. 2. Destruktorerna för den aktuella klassens datamedlemmar anropas 3. Destruktorn för ev. överklass anropas. baklänges enligt deriveringslistans turordning Sid 13 Sid 14

39 Lite OOA/OOD Förenklad Projektmodell Kravspecifikation (tillsammans med kund) Case Studies (Hur skall systemet användas) Design (Klassdiagram med relationer) Interaction Diagrams (Vem anropar när) Iterativ process, men se upp för hävstångsverkan. Fel blir allvarligare ju tidigare dom införs! Sid 1 Sid 2 Kravspecifikation Studera Use Cases Kunden vill ha ett spel med en jägare som jagar grodor. Dessa grodor kan gömma sig bakom diverse grunkor på spelplanen. En del grodor skjuter tillbaka om dom blir träffade. Andra grodor följer långsamt jägarens rörelser och kan förgifta honom. Sid 3 Informell teknik för att analysera krav: hitta användarroller - aktörer (actors) beskriv typfallen för hur de kan/ska interagera med systemet (användningsfall/use cases) Spelare Starta nytt Spel Röra sig på Skärmen Lägga till ny spelnivå bla Administratör Sid 4 Use Cases, forts Starta Spelet Spelaren väljer att starta ett nytt spel genom att starta programmet. Spelplanen byggs upp och väntar på att spelaren trycker på en knapp för att starta. Röra Sig på Skärmen(4 stycken) Spelaren rör sig över skärmen genom att trycka 6. Spelarens jägare flyttas då till höger om det går. Om det står en farlig groda på den nya platsen dör jägaren. Finn Klasser och Relationer Skott Groda Jägare Sid 5 Sid 6

40 Klassdiagram(kap 6.2) Skott x y kaliber moveto(x,y) setcaliber() Namn Egenskaper Operationer (Metoder) Har (/Består av) -relation Composition (UML) Jägaren har (egentligen består av) ett gevär Ägaren ansvarar för konstruktion / destruktion Bil UML = unified modeling language. Motor Hjul Kaross Sid 7 Sid 8 Har - association Association Aggregat (UML) Samma som komposition, men Ägaren ansvarar inte för konstruktion / destruktion (Förut har vi använd association för att beskriva detta) Respektive leverantör ansvarar för sina varuställ SuperMarket Mjölk Bröd Läsk Känner till (utan att äga). Förut använde vi detta för att beskriva relationen aggregat som vi nu har en egen symbol för. Kan även beskriva andra relationer. Noll eller flera grodor känner till noll eller en Jägare Groda 0..* 0..1 Jägare En jägare skjuter ingen eller max 3 grodor Skjuter 1 Groda Jägare Sid 9 Sid 10 Multiplicitet Är- Relation Husdjur Relation kan vara: 1-1,1-M, M-1, M-M M=Många (Many) Om objektet i ena ändan ibland saknas: Pil kan ange riktning (kan även vara dubbelriktad) Obs! Pil kan även ange arv - pekar på föräldern Hund favoritben ät katt() pälsfärg smutsa ned() Kanin slaktvikt Katt klössoffa() Sid 11 Sid 12

41 Hund favoritben ät katt() Interface <<Interface>> IDraw Draw(dc:HDC) Erase(dc:HDC) IDraw IDraw Katt klössoffa() Sid 13 IBodyImpl x:int y:int Identifiera Klasser och Interface <<implements>> Efter några iteratoner <<interface>> IBody moveto(x,y) GetX:Int GetY:Int IDraw <<implements>> Bullet <<implements>> IBody <<Interface>> IDraw Draw(dc:HDC) Erase(dc:HDC) <<implements>> <<uses>> Sworm IDraw Elements:IBody Add(e:IBody) Step Detach Vector<IBody> Sid 14 Interaction Diagram (från Spelare Trycker Space WM_CHAR Game Board New newbullet: Bullet Init bullets: Sworm Add Sid 15 Sid 16 Interaction Diagram Windows Game Board bullets: Sworm currentbullet: Bullet WM_TIMER Step Erase GetX,GetY MoveTo Draw Repeat For all bullets in Sworm WM_TIMER on frogs works in exactly the same way Sid 17

42 Eller class Function Template (Funktionsmall) template <typename T> void myfunc(t * arr, int n) // objekt av typ T kan // deklareras och // användas inom funktionen Explicit / Implicit instansiering, T byts mot aktuell typ T döljer ev. T deklarerat före mallen Sid 1 Class Template (Klassmall) template <typename T> class Stack void push(const T& item); const T& pop(); private: T* m_memory; Instansiering görs explicit enligt: Stack<int> my_stack; T byts mot aktuell typ Eller class Sid 2 Template non-type parameter+defaults template <typename T = string, int size = 1024 > class Stack Stack()m_memory = new T[size]; void push(const T& item); const T& pop(); private: T* m_memory; Sid 3 Klassmall forts Medlemsfunktioner definierade utanför klassdeklarationen måste också göras till mallar: template <typename T> void Stack<T>::push( const T& item) // implementation Sid 4 Template som argument Man använder ibland template i template, men se upp! vector<stack<int>*> vstacks;... vector<stack<int> > vstacks;... Sid 5 Om klassvariabler definieras i en klassmall får varje instansiering sin egen uppsättning. Klasser inuti klasser kan göras även med mall. Den inre klassen kan använda den yttre klassens mall-parametrar. Medlemsfunktioner och nästade klasser i en klassmall kan ha egna typparametrar oberoende av klassmallens, member template detta används i abstrakta containertyper Sid 6

43 Friends (vänner) i klassmallar Följande kan vara vänner till klassmallar : Klass eller funktion som inte är mall Klass eller funktion som är mall, bunden till klassmallen genom att den använder klassmallens typparameter Klass eller funktion som är mall, obunden, dvs med egen typparameter oberoende av klassmallens Sid 7

44 Felhantering Exempel (felhantering) Felhantering i C är ganska besvärlig Oftast returneras felmeddelanden från funktioner. Returvärdena måste sedan kontrolleras samt hantera eventuella fel Om en funktion returnerar ett objekt är det svårt att bestämma när ett fel har uppstått. Kan ge konstiga konstruktioner CD5250 Sid 1 float dividera(float taljare, float namnare) // hur hanterar vi division med noll? return taljare/namnare; ; // division med noll! float resultat = dividera(5.0f, 0.0f); // vad är ett felaktigt returvärde i // detta fall? CD5250 Sid 2 Exempel (felhantering C) Exceptions int dividera(float taljare, float namnare, float* result) if (namnare == 0) return -1; *result = taljare/namnare; return 0; ; float resultat; int retur = dividera(5.0f, 0.0f, &resultat); if (retur == -1) // Division med noll!! CD5250 Sid 3 Exceptions kan användas när det uppstår undantagsfel i programmet Exempelvis om minnet tar slut, inläsning av en trasig fil, avbruten kommunikation m.m. Exceptions ger fördelen att programmeraren kan förutsätta att allt går bra, men ifall det skulle uppstå problem så kan dessa hanteras CD5250 Sid 4 Exceptions Exceptions Ett exception slängs med operatorn throw Valfritt objekt kan slängas Klasshierarkier med olika Exception-objekt kan med fördel användas Objektet returneras bakåt i anropshierarkin tills det fångas av en try catch rutin Exceptions kan ge en felhantering på hög nivå Felet behöver inte tas omhand i den felande funktionen eller i den direkt anropande funktionen Hantering av fel är inte alltid möjlig i den direkta närheten där felet uppstår, men kan med exceptions hanteras högre upp i anropshierarkin CD5250 Sid 5 CD5250 Sid 6

45 Exempel (felhantering C++) int result; try result = dividera(5.0f, 0.0f); catch (char * str) // Division med noll!! <stdexcept> exception logic_error runtime_error bad_alloc out_of_range length_error range_error bad_cast float dividera(float taljare, float namnare) if (namnare == 0) throw Division by zero ; return taljare/namnare; ; CD5250 Sid 7 invalid_argument domain_error overflow_error underflow_error CD5250 Sid 8 Flera catch-uttryck try File file( c:\kalle.txt ); string str = file.readstring(); catch (OutOfMemoryException e) // Slut på minne vid inläsning catch (BadFileFormatException e) // Felaktigt filformat catch (Exception e) // Andra standardfel som kan uppstå catch () // Fånga ALLA andra fel här (DivisionByZero m.fl.) CD5250 Sid 9 Flera catch-uttryck Ett try-catch block kan ha flera catchuttryck för att hantera flera olika fel Endast ett catch-uttryck exekveras Det första som matchar Ellipsis ( ) fångar alla fel Om denna används bör den vara sist av catchuttrycken CD5250 Sid 10 Slänga undantagsfel Skicka vidare exceptions Syntax: throw 4; throw Klass; throw Klass(konstruktorparametrar); Flera olika undantagsfel (objekt) kan slängas från en metod, men endast en i taget En metod kan behöva fånga undantagsfel utan att kunna hantera felet Exempelvis kan en metod avallokera minne för att undvika minnesläckage. För att sedan vidare hantering av felet skall ske så kan metoden skicka vidare felet med throw; i catchuttrycket CD5250 Sid 11 CD5250 Sid 12