36
Föreläsning 4

Föreläsning 4

  • Upload
    vachel

  • View
    81

  • Download
    0

Embed Size (px)

DESCRIPTION

Föreläsning 4. Arv – bakgrund (kap. 9). Katt pälsfärg smutsa_ned() klös_soffa(). Hund pälsfärg favoritben smutsa_ned() ät_katt(). Kanin pälsfärg slaktvikt smutsa_ned(). Arv – bakgrund. Många klasser delar på egenskaper och beteende - PowerPoint PPT Presentation

Citation preview

Page 1: Föreläsning  4

Föreläsning 4

Page 2: Föreläsning  4

Arv – bakgrund (kap. 9)

Hund

pälsfärg

favoritben

smutsa_ned()

ät_katt()

Katt

pälsfärg

smutsa_ned()

klös_soffa()Kanin

pälsfärg

slaktvikt

smutsa_ned()

Page 3: Föreläsning  4

Arv – bakgrund

• 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

Page 4: Föreläsning  4

Problemlösningsmetodik

• Börja med att identifiera alla klasser som behövs

• Leta sedan efter beteenden som är gemensamma för flera klasser– Bryt ut i en överklass

• Kontrollera även om det redan finns passande klasser

Page 5: Föreläsning  4

LösningHusdjur

pälsfärg

smutsa ned()

Katt

klösSoffa()

Kanin

slaktvikt

Hund

favoritben

ät katt()

Page 6: Föreläsning  4

Implikationer av arv

• 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

Page 7: Föreläsning  4

Implikationer av arv

• Underklassens beteende är mer specialiserat

• Överklassens beteende är mer generellt• Klasser som är mycket generaliserade

är ofta abstrakta och kan inte instansieras– Husdjur– Fordon

Page 8: Föreläsning  4

Vad ärvs?

• Medlemsfunktioner ärvs• Datamedlemmar ärvs• Friends (vänner) ärvs inte• Konstruktor ärvs inte

– Basklassens (överklassen) konstruktor anropas via initieringslistan

Page 9: Föreläsning  4

Fordonclass Fordon{public: Fordon(Person & owner) : m_owner(owner) {} Point GetPosition() { return m_position; } Person & GetOwner() { return m_owner; }protected: Point m_position; Person & m_owner;};

// Fordon initierar owner & position i sin// initieringslistaFordon(Person & owner) : m_position(10,5), m_owner(owner){}

Page 10: Föreläsning  4

Bil ärver från Fordon// Ärver från Fordonclass Bil : public Fordon{public: Bil(Person & owner); void TurnWheel(float wheel); protected: float m_wheelpos;}

// Bilkonstruktorn anropar överklassens konstr.// OBS likheten med initieringslista av variablerBil::Bil(Person & owner) : Fordon(owner){ m_wheelpos = 0;}

Page 11: Föreläsning  4

Alltså är en Bil ett Fordon

// vi kommer åt alla Fordons medlemsvariablervoid Bil::TurnWheel(float wheel){ m_wheelpos = wheel; int x = GetPosition().GetX();

// vi kan använda m_owner som är deklarerad // i klassen Fordon cout << ”Bilen med ägare ” << m_owner.Name() << ” svänger med ratten” << endl;}

Page 12: Föreläsning  4

Motorcykel ärver från Fordon// Ärver från Fordonclass Motorcykel : public Fordon{public: 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;}

Page 13: Föreläsning  4

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

Page 14: Föreläsning  4

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()

Page 15: Föreläsning  4

Synligt arv (public)(kap. 9.3)

• Synliga (public) medlemmar i överklassen blir synliga i underklassen

• Skyddade (protected) medlemmar i överklassen blir skyddade i underklassen

• Privata (private) medlemmar i överklassen kommer man inte åt från underklassen

Page 16: Föreläsning  4

Skyddat arv (protected)

• Synliga (public) medlemmar i överklassen blir skyddade (protected) i underklassen

• Skyddade (protected) medlemmar i överklassen blir skyddade i underklassen

• Privata (private) medlemmar i överklassen kommer man inte åt från underklassen

Page 17: Föreläsning  4

Privat arv (private)

• Synliga (public) och Skyddade (protected) medlemmar i överklassen blir privata (private) i underklassen

• Privata (private) medlemmar i överklassen kommer man inte åt från underklassen

Page 18: Föreläsning  4

Tillgänglighet – översikt

i överklass typ av arv i underklass

public public publicprotected public protectedprivate public ej åtkomlig

public protected protectedprotected protected protectedprivate protected ej åtkomlig

public private privateprotected private privateprivate private ej åtkomlig

Page 19: Föreläsning  4

Minneslayout

Fordon

Person & ägare

Point position

Bil

Person & ägare

Point position

float wheelpos

Motorcykel

Person & ägare

Point position

int color

• Nya datamedlemmar läggs till i slutet av klassen, ärvda medlemmar ligger alltid på samma offset i minnet

Page 20: Föreläsning  4

Statisk allokering

• 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

!

Page 21: Föreläsning  4

Exempel (slicing)

Person owner(”kalle”);Bil b(owner);Fordon f = b; // SLICING!!!

Fordon *f2 = &b; // OK

Page 22: Föreläsning  4

Exempel(tillgänglighet vid arv)

class Stack : private Vector{public: void push(Elem e)

{/* peta i vektorn */} Elem pop()

{/* peta i vektorn */}};

// main... Stack s;Elem e,e1,e2;…s.push(e1);s.push(e2);e=teststack.pop();

Vi får ett väldigt fult anropssnitt!t=teststack[10];teststack.push_back(e);

Privat eller skyddat arv

Vad händer om man använder public inheritance istället?

Page 23: Föreläsning  4

…en stack är inte en vektor

• Snyggare och bättre med en vektor som beståndsdel (aggregat) istället för arv

class Stack{public: push(Elem e) { theStack.pushBack(e); } Elem pop() { /* ... */ }private: Vector theStack;};

Page 24: Föreläsning  4

Konstruktor (kap. 9.2)

• När ett objekt skapas sker följande1. Konstruktorn för ev. överklass anropas

alltid först2. Konstruktorerna för den aktuella klassens

datamedlemmar anropas3. Satserna i den aktuella klassens

konstruktor exekveras

Page 25: Föreläsning  4

Konstruktoranrop

• Konstruktorn för en överklass kan anropas via underklassens konstruktor– Bil::Bil(Person & owner) : Fordon(owner)…

• Om ingen konstruktor för överklassen specificeras anropas överklassens defaultkonstruktor

Page 26: Föreläsning  4

Destruktor

• När ett objekt tas bort sker följande1. Satserna i den aktuella klassens

destruktor exekveras2. Destruktorerna för den aktuella klassens

datamedlemmar anropas3. Destruktorn för ev. överklass anropas

Page 27: Föreläsning  4

Konstigheter vid arv

• Funktionsöverlagring– Metoder deklarerade i en subklass döljer

alla metoder med samma namn i basklassen, oavsett vilka parametrar metoderna har

Page 28: Föreläsning  4

Arv – fördelar (kap. 9.4)

• Arv kan som vi har sett underlätta programmering genom att olika klasser kan dela på gemensam källkod

• Arv för även med sig andra fördelar. När ett objekt ärver från en överklass garanterar vi att underklassen klarar allt som överklassen klarar

Page 29: Föreläsning  4

Användning av arv// skriv ut information om ett fordonvoid Fordonsinfo(Fordon & fordon){ // alla fordon har en ägare Person & owner = fordon.GetOwner();

cout << ”Fordonet har en ägare vid namn ” << owner.Name(); }

Person owner1(”kalle”);Person owner2(”olle”);Bil b(owner1);Motorcykel m(owner2);

// vi kan behandla ”m” och ”b” som FordonFordonsinfo(b); // skriver ut ”kalle”Fordonsinfo(m); // skriver ut ”olle”

Page 30: Föreläsning  4

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

Page 31: Föreläsning  4

Exempel (multipelt arv)

Bil Båt

Amfibiebil

• Amfibiebil ärver alla egenskaper som bil och båt har

• En Amfibiebil är en Bil och en Båt

Page 32: Föreläsning  4

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

Page 33: Föreläsning  4

Exempel (Amfibiebil)class Bil{public: Bil(int age) { m_age = age; } void Print() { cout << ”Bil, årsmodell ” << m_model; }protected: int m_model;};

class Bat{public: Bat(int length) { m_length = length; } void Print() { cout << ”Båt, längd ” << m_length; }protected: int m_length;};

Page 34: Föreläsning  4

Exempel (Amfibiebil) forts.

class Amfibiebil : public Bil, public Bat{public: 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(); }};

Page 35: Föreläsning  4

Exempel (multipelt arv)

Fordon

Bil Båt

Amfibiebil

Page 36: Föreläsning  4

Konstigheter med multipelt arv

• 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