Dynamisk bindning och polymorfism I C++ är pekare till basklasser polymorfa, dvs de kan peka på objekt av en subklass typ Vid statisk bindning sker all bindning vid kompileringen -> Vid ett metodanrop är det den polymorfa pekarens typ som avgör vilken metod som avses Vid dynamisk bindning sker bindningen inte förrän programmet körs -> Vid ett metodanrop är det typen på det pekaren pekar på som avgör vilken metod som avses 112 Virtuella funktioner Statisk bindning är default - nyckelordet virtual används för att få dynamisk bindning virtual double getarea(); class Rect : public Figur double b,h; double getarea() return b*h; // virtuell 113 Virtuella anrop med pekare class Circ: public figur double r; double getarea() return 3.14*r*r; Figur *fp[2]; fp[0]=new Circ(5) fp[1]= new Rect(3,4); for(int i=0;i<2;i++) cout << Area << fp->getarea(); 114 Virtuella anrop med referens void skrivutarea(figur& f) cout << Arean är << f.getarea() <<. ; Cirk jorden(40000000/m_pi/2); skrivutarea(jorden); Referensanrop behåller datat 115 Virtuell destruktor Basklasssens destruktor anropas for (int i=0;i<2;i++) delete fp[i]; // Frigör bara en figur Aktuella klassens destruktor anropas om den är virtuell virtual ~Figur(); Frigörs ej 116 Abstrakt basklass Fångar gemensamma egenskaper Påtvingar ett gränssnitt Går ej skapa objekt från Med äkta (pure) virtuell funktion: virtual double getarea() = 0; Eller med protected konstruktor 117 1
Konstruktorer, destruktorer Hur skapar man objekt, och vad händer då Allt som skapas måste tas bort Överlagrade metoder Initiering med konstruktorer Destruktorer Initieringskonstruktor This-pekaren Konstruktorer Samma namn som klassen Ingen returtyp Ofta överlagrade Anropas av new, och vid allokering av automatiska variabler Kan misslyckas 118 119 En metod som alla andra Bil() 120 Konstruktorn anropas när objekt skapas Kan ta argument Bil b; //Default Bil b(10); Bil *b = new Bil(50); Bil *b = new Bil[50]; //Obs skillnaden Bil *b = new Bil[50](10); //Går ej! Finns ingen konstruktor anropas en default constructor, som inte gör någonting 121 Överlagrad konstruktor Initiering på kortform Bil() //Default Bil(int hast) // med argument hastighet = hast; 122 Bil() //Default Bil(int hast) : hastighet(hast) 123 2
Statiska objekt Dvs globala objekt Garanterat initierade före main startar Ordningen ej förutsägbar -> problem! Ett objekt kanske behövs av konstruktorn i ett annat, men är inte skapat ännu #include Bil.h #include Passagerare.h Bil b; Passagerare p; void main Defaultvärden Kan användas av alla metoder Vanligt vid konstruktorer Bil(int hast = 0) hastighet =hast; Bil b; -> ger hastighet = 0 Bil b(12); -> ger hastighet = 12 124 125 Återanvändning? En konstruktor kan i princip anropa en annan, men det kan leda till problem Bättre att låta defaultkonstruktorns arbete utföras av en annan metod På så sätt kan alla konstruktorer dela på metoden 126 Konstruktorer och arv En konstruktor i en subklass kan anropa basklassens konstruktor class Fordon Fordon(int hast) : hastighet (hast : public Fordon Bil(int hast = 0) : Fordon(hast) cout << hastighet << hast; 127 Vi använder new, sen då? Destruktorer Hur deallokera objekten? ->Explicit Problem men dangling pointers C++ har delete -> Implicit Vi behöver Garbage Collection i någon form Java har GC Anropas när ett objekt tas bort Antingen med delete Eller automatisk deallokering av lokala variabler Samma namn som konstruktorn men med ett tilde (~) framför Inte lika mycket använda som konstruktorer, men en god regel är att alltid ha med en! 128 129 3
Bil(int hast = 0); ~Bil() Bil::Bil(int hast) hastighet=hast; Bil::~Bil() Destruktorer forts. Alla metoder i klassen måste ha en implementation, även om den är tom Vill man inte skriva en tom konstruktor så utelämna deklarationen -> default delete används för att ta bort ett objekt som allokerats med new Använd utskrifter i konstruktorer/destruktorer under utvecklingen! 130 131 #include Fordon.h #include Bil.h int main() Bil b; // konstr b Bil *p= new Bil(10); // konstr *p delete p; // destr *p // destr b 132 Virtuell destruktor Har att göra med dynamisk bindning Gör att rätt destruktor anropas class Fordon Fordon(int hast) : hastighet(hast) virtual ~Fordon(); : public Fordon Bil(): Fordon (0) Bil(int hast) : Fordon(hast) virtual ~Bil(); 133 En sorts konstruktor till Initieringskonstruktorn Initieringskonstruktor (Copy constructor) Anropas när en kopia av ett givet objekt skall göras Kan anropas utan att du vet om det tex vid metodanrop Om djup kopiering krävs är en initieringskonstruktor ett måste Använd i fyra fall: V b=a; - Initiering av objekt från annat void fkn(v b) fkn(a); -Parameteröverföring V fkn() V t; return t; - init av returvärde d=a+b*c; - kompilatorn skapar temporär t=b*c 134 135 4
Forts. char *namn; Bil () namn=0; Bil (char *n) namn = new char[strlen(n)+1]; strcpy(namn,n); Bil (Bil &b) namn = new char[strlen(b.namn)+1]; strcpy(namn,b.namn); virtual ~Bil () delete [] namn; 136 Obs initiering <> tilldelning! int main() Bil b( bmv ); Bil kopia(b); //initiering Bil c=b; //Initiering funk(b); c = b; return 0; // kan bli init //tilldelning 137 Problem Har en klass en konstruktor som bara tar en parameter -> Automatisk konvertering från typen på parametern till klasstypen Lösning explicit : class V V(int v) void vprint(v thev) vprint(1) //Automatisk konv av 1 till V 138 This-pekaren Använd om man behöver en pekare till det objekt som metoden körs i Alla klassmetoder har en this-pekare som osynligt argument Statiska metoder har ingen this-pekare Bil (int hastighet) this -> hastighet = hastighet; 139 5