Kommentarer till Person



Relevanta dokument
TDDC76 PoD OH Föreläsning C Härledda klasser

Tommy Färnqvist, IDA, Linköpings universitet

Skapa, kopiera och destruera klassobjekt

Operatoröverlagring. endast operatorsymboler definierade i C++ kan överlagras = += -= *= /= %= ^= &= = <<= >>= < > <= >= ==!= && > ->*, [ ] ( )

Innehåll. 1 Kort om dynamisk polymorfism. 2 Arv i C++ 3 Multipelt arv. 4 Något om statisk polymorfism. class Container {

Programmering i C++ EDA623 Arv. EDA623 (Föreläsning 6) HT / 42

Innehåll. Konstruktorer vid arv Regler för basklassens konstruktor. Konstruktorer vid arv. Konstruktorer vid arv. Konstruktorer vid arv

TDDC76 - Programmering och Datastrukturer

Programsystem konstruktion med C++ (2D1387) Innehåll. övning 2 klasser och arv

Lektionsuppgifter. TDDI14 Objektorienterad programmering. Lektionsplanering Lektion Lektion Lektion

TDIU01 Programmering i C++

Del2 Klasser, medlemmar och arv Ämnesområden denna föreläsning:

Innehåll. Typomvandlingar (casting) Implicita Typomvandlingar. Typomvandlingar (casting) Implicita Typomvandlingar

TDDC76 - Programmering och Datastrukturer

Introduktion till arv

Objektorientering - Arv och polymorfi. Eric Elfving Institutionen för datavetenskap

Dynamisk bindning och polymorfism

Introduktion. Klasser. TDP004 Objektorienterad Programmering Fö 2 Objektorientering grunder

Innehåll. Pekaren this Självreferens. Klasser Resurshantering, representation. Överlagring av operatorer. Överlagring av operatorer

Klasser. Kapitel 2. Kapitel 2 - Klasser, medlemmar och arv. Klasser. Klasser Medlemmar Arv

TDDC76 - Programmering och Datastrukturer

Kopiering av objekt i Java

Programsystemkonstruktion med C++: Övning 2. Karl Palmskog september 2010

TDDC76 Programmering och datastrukturer

Programmering i C++ EDA623 Objektorienterad programutveckling. EDA623 (Föreläsning 5) HT / 33

TDDI14 Objektorienterad programmering

Arv. Objektorienterad och komponentbaserad programmering

OOP Objekt-orienterad programmering

TDIU20 - Objektorienterad programmering i c++ - föreläsning 6

UML. Klassdiagr. Abstraktion. Relationer. Överskugg. Överlagr. Aktivitetsdiagram Typomv. Typomv. Klassdiagr. Abstraktion. Relationer.

Innehåll. Typomvandlingar (casting) Implicita Typomvandlingar. Typomvandlingar (type casts) Explicita, namngivna typomvandlingar (C++-11)

Objektorienterad programmering Föreläsning 12. Copyright Mahmud Al Hakim

Övriga byggstenar. Övriga byggstenar. Några tips under programutveckling. Beroenden Pekare till funktioner Typkonvertering

C++ Objektorientering - Klasser. Eric Elfving

Polymorfi. Objektorienterad och komponentbaserad programmering

Föreläsning 5 (6) Metoder. Metoder Deklarera. Metoder. Parametrar Returvärden Överlagring Konstruktorer Statiska metoder tostring() metoden javadoc

Trädtraversering. Binärt träd. Trädtraversering djupet-först. Trädtraversering bredden-först

Innehåll. Pekare Exempel

Föreläsning 8. Arv. Arv (forts) Arv och abstrakta klasser

Innehåll. Pekare Exempel

KLASSER. Inkapsling Abstrakt datatyp Public och private. Klassmedlemmar Datamedlemmar Exempel Funktionsmedlemmar

5 Arv och dynamisk bindning FIGUR

allokeras på stacken dynamiskt new delete

Minneshantering. Minneshantering. Minneshantering. Undvik pekare

Del3 Klassanvändning, operatorer och pekare Ämnesområden denna föreläsning:

Objektorientering - Arv och polymorfi

DAT043 - Föreläsning 7

Nedan skapar vi klassen Person innehållande datamedlemmar för förnamn, efternamn, ålder, längd och vikt:

Outline. Objektorienterad Programmering (TDDC77) Att instansiera en klass. Objekt. Instansiering. Åtkomst. Abstrakt datatyp.

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

Kommentarer till boken

Programsystemkonstruktion med C++

Tentamen i TDP004 Objektorienterad Programmering Lösningsförslag

Synlighet. Namespace Scope-operatorn Klasser Vänner

Kapitel 3. Synlighet. Kapitel 3 - Klassanvändning, operatorer och pekare. Synlighet

Programmering i C++ EDA623 Mer om klasser. EDA623 (Föreläsning 6) HT / 26

"Är en"-relation. "Har en"-relation. Arv. Seminarium 2 Relevanta uppgifter. I exemplet Boll från förra föreläsningen gällde

Arv innebär att man skapar en ny klass (subklass) utifrån en redan existerande klass (superklass, basklass).

TDDC76 - Programmering och Datastrukturer

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 2 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Objektorienterad Programmering (TDDC77)

OOP Objekt-orienterad programmering

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 14

C++ Objektorientering - Klasser. Eric Elfving Institutionen för datavetenskap

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

DD2387 Programsystemkonstruktion med C++ Tentamen 1 Torsdag 7 januari 2016, 14:00-18:00

2I1049 Föreläsning 5. Objektorientering. Objektorientering. Klasserna ordnas i en hierarki som motsvarar deras inbördes ordning

Arv bakgrund (kap. 9)

Java, klasser, objekt (Skansholm: Kapitel 2)

Innehåll. Användardefinierade typer. Användardefinierade typer Kategorier. Konstruktorer. Konstruktorer Två sätt att skriva initiering av medlemmar

TDDE10 TDDE11, 725G90. Objektorienterad programmering i Java, Föreläsning 3 Erik Nilsson, Institutionen för Datavetenskap, LiU

Tillämpad programmering

Objektorienterad programmering Föreläsning 5

Objektorienterade programmeringsspråk. Objektorienterade språk. Den objekt-orienterade modellen. Jämför med icke-oo

TDDC76 PoD OH Föreläsning C Klasser

Klassmedlemmar. Klasser. Konstruktion av en enskild, icke-trivial klass. Klassen String funktionalitet

Malmö högskola 2007/2008 Teknik och samhälle

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Static vs Dynamic binding Override vs Overload. Objekt-orienterad programmering och design Alex Gerdes och Sólrún Halla Einarsdóttir, 2018

OOP Objekt-orienterad programmering

1. Klass med en dynamiskt allokerad variabel, definitionsfilen-del Klass med en dynamiskt allokerad variabel, inkluderingsfilen.

F8: Typkonvertering i C++

Kapitel 6 - Undantag

TUTORIAL: KLASSER & OBJEKT

Föreläsning 4. Klass. Klassdeklaration. Klasser Och Objekt

Classes och Interfaces, Objects och References, Initialization

Exempelvis pekarvariabler blir då lättare korrekt deklarerade och initierade.

Outline. Objektorienterad Programmering (TDDC77) Signatur. Klassen calculator. Överlagring (overloading) Arv (inheritance) Ahmed Rezine

Tentamen i TDP004 Objektorienterad Programmering Teoretisk del

TENTAMEN CD5250. Objektorienterad programutveckling med C++, 5p. Datum: , Tid: 14:00-19:00

Objektorienterad Programmering (TDDC77)

Innehåll. Introduktion till objektorientering. OOP (objektorienterad programmering) Objekt, instanser, klasser

Del2 Klasser, medlemmar och arv Ämnesområden denna föreläsning:

Objekt och klasser - Introduktion. Objekt. SparKonto.java 2. SparKonto.java 1. Konton.java. Ett objekt har: Ett bankkonto

1 Namnkontroll (NameControl)

Tentamen EDAF30 Programmering i C++

Vad är en klass? Övning 2. Konstruktorer. ffl copy-konstruktorn tar en instans av klassen som. ffl default-konstruktorn tar inga argument och kan

Idag. Javas datatyper, arrayer, referenssemantik. Arv, polymorfi, typregler, typkonvertering. Tänker inte säga nåt om det som är likadant som i C.

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

Transkript:

TDDC76 PoD OH Föreläsning C++ 97 Härledda klasser TDDC76 PoD OH Föreläsning C++ 98 --Manager-Consultant en polymorf klasshierarki C++ har en relativt komplett och därmed komplicerad modell för härledning/arv stödjer flera sätt för subklasser att ärva från sina basklasser enkelt arv endast en direkt basklass multipelt arv två eller flera direkta basklasser upprepat arv en indirekt basklass ärvs flera gånger via multipelt arv multipelt och upprepat arv kan leda till tvetydigheter och andra problem behov av mekanismer för att lösa detta flera sätt att specificera tillgänglighet för basklassmedlemmar i den härledd klass public basklass public-medlemmar i basklassen blir public i den härledda klassen (protected blir protected) protected basklass public-medlemmar i basklassen blir protected i den härledda klassen (protected blir protected) private basklass public-medlemmar i basklassen blir private i den härledda klassen (protected blir private) tillgängligheten är public om basen är en struct, private om en class ifall inget anges en klass kan utse vänner en friend har åtkomst till alla medlemmar, även privata polymorft beteende bestäms av programmeraren objekt som ska bete sig polymorft måste refereras via pekare eller referenser endast anrop av virtuella medlemsfunktioner kan bindas dynamiskt och därmed uppvisa polymorft beteende en icke-polymorf klasshierarki använder arv för återanvändning av kod för, i princip, fristående klasser Konstruktion av en enkel polymorf klasshierarki för att hantera anställda (employees) vid ett företag. en klass för att representera personer i allmänhet har namn och personnummer (civic registration number) alla anställda ska dela egenskaperna hos denna klass inga objekt ska kunna skapas ska vara en abstrakt klass en klass för anställda i allmänhet har anställningsdatum, anställningsnummer, lön, anställning vid en avdelning mer specialiserade kategorier av anställda ska härledas från denna klass objekt ska kunna skapas ska vara en konkret klass en klass för anställda som är avdelningschefer Manager ansvarar för en avdelning och dess anställda en klass för (tillfälligt) anställda som är konsulter Consultant ingen direkt skillnad jämfört med en anställd i allmänhet men ska vara särskiljbar typmässigt objekt skapas typiskt dynamiskt och hanteras med pekare annars inget polymorft beteende hos objekt Observera, I det fullständiga kodexemplet har medlemsfunktioner som implementeras med endast en rad definierats i klassdefinitionerna i exemplen som visas på följande sidor deklareras endast funktionerna av utrymmesskäl. Manager Consultant TDDC76 PoD OH Föreläsning C++ 99 Class TDDC76 PoD OH Föreläsning C++ 100 Kommentarer till class virtual ~() = default; // HIC++ 12.5.2 virtual std::string str() const; virtual * clone() const = 0; std::string get_name() const; void set_name(const std::string&); CRN get_crn() const; void set_crn(const CRN&); (const std::string& name, const CRN& crn); (const &) = default; // HIC++ 12.5.2 & operator=(const &) = delete; // HIC++ 12.5.8 ; std::string name_; CRN crn_; defaultkonstruktor, flyttkonstruktor och flyttilldelningsoperator genereras e alla speciella medlemsfunktioner som annars skulle ha genererats implicit är deklarerade (kodningsregel) i grunden en trivial klass välartade datamedlemmar båda har defaultkonstruktion och destruering de kompilatorgenererade speciella medlemsfunktionerna är i grunden bra men tillåts endast för ernt bruk defaulted (= default) och deleted (= delete) medlemsfunktioner defaultkonstruktor i genereras e om någon annan konstruktor deklareras kan defaultas om önskad kopieringstilldelning ska e vara tillåten åtkomstspecifikationen är betydelselös men underförstått private om deleted flyttilldelning genereras e om destruktor, kopieringskonstruktor eller kopieringstilldelningoperator deklareras regel: deklarera alltid speciella medlemsfunktioner som annars hade genererats för att tydligt dokumentera gränssnittet virtuella funktioner (virtual) virtuella funktioner kan överskuggas av subklasser deklarera med override (HIC++ 10.2.1) sker om en funktion med samma signatur deklareras i en subklass deklarera e virtual i subklasser gör klassen polymorf pure virtual funktion pure specifier = 0 gör att en virtuell funktion e kan anropas en publik medlem kan ha en separat definition måste om en destruktor anropbar från andra medlemsfunktioner och subklassers medlemsfunktioner pure virtual funktioner ärvs en subklass blir också abstrakt såvida e alla ärvda pure virtual funktioner överskuggas gör klassen abstrakt

TDDC76 PoD OH Föreläsning C++ 101 Kommentarer till, forts. polymorf klass har virtuella funktioner, egna eller ärvda måste ha en virtuell destruktor för att säkerställa korrekt destruering av subobjekt (HIC++ 12.2.1) objekt kommer att innehålla typinformation används vid anrop av virtuella funktioner och av dynamic_cast objekts kommer att innehålla en virtuell tabell (t.ex. vtable) implementeringsteknik för anrop av virtuella funktions (skapas av kompilatorn) abstrakt klass inga fristående -objekt av kan skapas skyddade konstruktorer eftersom är abstrakt finns det inget behov av publika konstruktorer protected konstruktorer används för att framhäva abstraktheten inget annat syfte finns statisk typ och dynamisk typ TDDC76 PoD OH Föreläsning C++ 102 Konstruktor som tar namn och personnummer ::(const std::string& name, const CRN& crn) : name_ name, crn_ crn Säkerställer att en ny alltid har ett namn och ett personnummer defaultkonstruktorn genereras e ingen annan konstruktor är tillgänglig som kan initiera objekt på något annat sätt, utom kopieringskonstruktorn och flyttkonstruktorn ska endast användas av motsvarande konstruktor i subklasserna protected * p = new ( ); p->clone(); // p har statisk typ pekare till // den dynamiska typen för uttrycket *p är statisk typ används under kompilering för att kontrollera att clone() är tillåten för den typ av objekt p kan peka på dynamisk typ används vid exekvering för att binda den överskuggning av clone() som gäller för det objekt som p pekar på TDDC76 PoD OH Föreläsning C++ 103 Medlemsfunktionen str() virtual std::string str() const; Definition: string ::str() const return name_ + + crn_.str(); Anrop kommer att bindas dynamiskt, om objektet refereras av pekare eller referens. den dynamiska typen avgör vilken överskuggning som anropas * p new Managername, crn, date, employment_number, salary, dept ; cout << p->str() << endl; TDDC76 PoD OH Föreläsning C++ 104 Medlemsfunktionen clone() virtual * clone() const = 0; Polymorfa klasser behöver ibland en polymorf kopieringsfunktion. använder man polymorfa klasser innebär det ibland att man ska allokera objekten dynamiskt och hanterar dem via pekare kräver en polymorf kopieringsfunktion som clone() varje konkret subklass måste ha sin egen, specifika överskuggning av clone() lämplig kandidat för att göra abstrakt inga fristående -objekt ska kunna skapas deklareras pure virtual, = 0 (pure specifier) ingen definition ska (kan) finnas i detta fall standardbibliotekets strömklasser är exempel på polymorfla klasser som e ska kunna kopieras saknar publik kopieringskonstruktor pekaren p har statisk typ * uttrycket *p har dynamisk typ Manager (*p).str() Manager::str() anropas vi föredrar piloperatorn i detta fall p->str()

TDDC76 PoD OH Föreläsning C++ 105 TDDC76 PoD OH Föreläsning C++ 106 Subklassen class : public (const std::string& name, const CRN& crn, e_number, salary, dept = 0); ~() = default; // HIC++ 12.5.1, 12.5.2 ; & operator=(const &) = delete; // HIC++ 12.5.1 friend class Manager; void set_department( dept); void set_salary( salary); IDA_date::Date e_date_; e_number_; salary_; dept_; // HIC++ 11.2.1 (använd e friend) std::string str() const override; // HIC++ 10.2.1 * clone() const override; // observera returtypen kovariant med * get_department() const; Date get_employment_date() const; get_employment_number() const; get_salary() const; (const &) = default; // HIC++ 12.5.1, 12.5.2 TDDC76 PoD OH Föreläsning C++ 107 Kommentarer till trivial klass samma överväganden som för ett -objekt består av ett subobject av typ och de specifika datamedlemmarna för -subobjektet initieras före medlemmarna i -subobjektet destrueras efter att medlemmarna i har destruerats det enda sättet att överföra argument till en konstruktor i är med en medlemsinitierare båda virtuella funktionerna överskuggas ska ha specifika versioner av både clone() och str() ska vara en konkret klass clone() måste överskuggas och definieras märk en virtuell funktion override (HIC++ 10.2.1) kompilatorn kontrollerar att det verkligen finns en sådan funktion i basklassen att överskugga virtual deklareras e (har ingen inverkan; var god kodningsstil i C++03) Manager är deklarerad som friend alla medlemsfunktioner hos Manager har obegränsad åtkomst till alla medlemmar hos, även private-medlemmar vänskap skapar starkare koppling än härledning härledning ger e åtkomst till private-medlemmar (HIC++ 11.2.1) anledningen till att deklarerar Manager som vän sparar vi lite TDDC76 PoD OH Föreläsning C++ 108 Publik konstruktor för ::(const string& name, const CRN& crn, e_nbr, salary, dept) : name, crn, e_date_e_date, e_number_e_nbr, salary_salary, dept_dept -subobjektet initieras per definition först -initieraren ska finnas först i initierarlistan anrop av motsvarande konstruktor i s egna datamedlemmar initieras sedan i deklarationsordning skriv deras initierare i samma ordningen en konstruktor ska uttryckligen initiera alla basklasser och icke-statiska datamedlemmar (HIC++ 12.4.2, 12.4.4)

TDDC76 PoD OH Föreläsning C++ 109 Medlemsfunktionen str() överskuggas string ::str() const return ::str() + " () " + e_date_.str() + ' ' + std::to_string(dept_); anropar str() för -subobjektet för att generera en del av strängen som ska returneras kvalificerat namn ::str() krävs för att undvika rekursion std::to_string() är överlagrad för alla grundläggande typer TDDC76 PoD OH Föreläsning C++ 110 Medlemsfunktionen clone() överskuggas virtual * clone() const return new *this ; ska skapa ett kopia av det objekt som anropar clone() och returnera en pekare till kopian kopieringskonstruktorn är den naturliga operationen för att göra kopian anropar i sin tur kopieringskonstruktorn för när returtypen tillhör en polymorf klasshierarki kan vi anpassa returtypen * p1 new name, crn, date, employment_nbr, salary ; * p2 = p1->clone(); // ingen typomvandling om clone() returnerar * * p3 = p1->clone(); // implicit typomvandling till * upcast typerna sägs vara kovarianta TDDC76 PoD OH Föreläsning C++ 111 Subklassen Manager TDDC76 PoD OH Föreläsning C++ 112 Kommentarer till Manager class Manager : public Manager(const std::string& name, const CRN& crn, e_number, salary, dept); ~Manager() = default; std::string str() const override; Manager* clone() const override; void add_department_member(* ep) const; void remove_department_member( e_number) const; void pr_department_list(std::ostream&) const; void raise_salary( percent) const; Manager(const Manager&) = default; Manager& operator=(const Manager&) = delete; ; // Manager äger e -objekten, destruering av dessa ska e utföras av Manager mutable std::map<, *> dept_members_; Manager trivial klass har en välartad datamedlem dept_members_ defaultinitieras till tom map för övrigt samma överväganden och åtgärder som för och ett Manager-objekt består av ett subobjekt av typ som i sin tur består av ett subobjekt av typ subklassobjekten deras datamedlemmar initieras uppifrån-och-ner och inom klasserna i deklarationsordning > > Manager destruering utförs i omvänd ordning och inom klasserna destrueras datamedlemmarna i omvänd deklarationsordning Manager > > str() överskuggas clone() överskuggas dept_members_ deklareras mutable add_department_member() och remove_department_member() deklareras som const-funktioner av logiska skäl mutable tillåter att dept_members_ modifieras även av const-funktioner Manager är friend till Manager försöker e komma åt privata medlemmar i så varför? vi får strax veta

TDDC76 PoD OH Föreläsning C++ 113 Publik konstruktor för Manager Manager(const std::string& name, const CRN& crn, e_number, salary, dept) : name, crn, e_date, e_number, salary, dept alla parametrar överförs som arguments till den direkta basklassen dept_members_ har defaultkonstruktion en tom lista med anställda skapas för en ny Manager TDDC76 PoD OH Föreläsning C++ 114 Medlemsfunktionenerna str() och clone() överskuggade string Manager::str() const return ::str() + " (Manager) " + get_employment_date().str() + ' ' + std::to_string(get_department()); virtual Manager* clone() const return new Manager *this ; Antag att vi skulle ha glömt att överskugga clone() för manager: den sista överskuggaren (last overrider) vore då ::clone() i stället för en Manager skulle clone() returnera en kopiera av -subobjektet i den Manager som skulle ha kopierats TDDC76 PoD OH Föreläsning C++ 115 Anställda på avdelningen hanteras av Manager TDDC76 PoD OH Föreläsning C++ 116 Consultant void Manager::add_department_member(* ep) const // Avdelningen för den anställda ska vara samma som avdelningschefens ep->set_department(get_department()); // vänskap behövs class Consultant final : public using ::; // ingen subklassning tillåten // konstruktorer ärvs // Lägg till i avdelningens lista över anställda dept_members_.insert(make_pair(ep->get_employment_number(), ep)); Manager måste vara friend till för att få anropa protected-medlemmen set_department() i denna kontext funktionsparametern ep är en pekare till endast public-operationer är tillåtna via ep, om e Manager är vän till om ep hade varit Manager* hade e friend behövts men det är ju e aktuellt En medlemsfunktion i Manager kan komma åt private-medlemmar i sig själv och i andra Manager-objekt kan komma åt protected-medlemmar egna och ärvda i sig själv och i andra Manager-objekt kan bara komma åt public-medlemmar i objekt av typ och Consultant, såvida e friend ~Consultant() = default; std::string str() const override; Consultant* clone() const override; Consultant(const Consultant&) = default; Consultant& operator=(const Consultant&) = delete; ; Consultant

TDDC76 PoD OH Föreläsning C++ 117 TDDC76 PoD OH Föreläsning C++ 118 Kommentarer till Consultant ingen egentlig skillnad jämfört med samma datamedlemmar, samma operationer samma publika konstruktorer ska finnas ärvs eller genereras vi vill kunna särskilja konsulter från vanliga anställda subtypning är ett sätt att möjliggöra det görs genom dynamisk typkontroll dynamic_cast eller typeid-uttryck märka en klass final class Consultant final : public det är e tillåtet att härleda från Consultant märka en virtuell funktion final virtual void str() const override final; en sådan funktion kan e överskuggas av subklasser används e i kodexemplet Consultant kommer att ha två publika konstruktorer, ärvda från Consultant(const std::string&, const CRN&, const Date&,, ); Consultant(const std::string&, const CRN&, const Date&,,, ); Initiering och destruering av objekt av härledd typ ett objekt av härledd typ består av delar, subobjekt subobjekt som motsvarar klassens basklasser klassens egna datamedlemmar initieringsordningen är uppifrån-och ner datamedlemmarna i ett basklass initieras före datamedlemmarna i en subklass första konstruktorn som anropas är konstruktorn för den mest härledda klassen den anropar sina direkta subklasskonstruktorer rekursivt datamedlemmarna i en klass initieras i den ordning de deklareras destrueringsordningen är omvänd mot initieringsordningen nerifrån-och-upp datamedlemmarna i en subklass destrueras före datamedlemmarna i en basklass först anropas den mest härledda klassens destruktor datamedlemmarna i klassen destrueras i omvänd deklarationsordning sist anropas de direkta basklassdestruktorerna, rekursivt viktigt att rotklassen i en polymorf klasshierarki har en virtuell destruktor annars avgör pekartypen vilken destruktor som körs * p new Consultant(...) ;... delete p; // ~() eller ~Consultant()? Manager Consultant TDDC76 PoD OH Föreläsning C++ 119 Använda,, Manager, Consultant * pp nullptr ; // kan peka på -, Manager- eller Consultant-objekt ( är abstrakt) * pe nullptr ; // kan peka på -, Manager- eller Consultant-objekt Manager* pm nullptr ; // kan endast peka på ett Manager-objekt Consultant* pc nullptr ; // kan endast peka på ett Consultant-objekt pm = new Manager name, crn, date, employment_nbr, salary, 17 ; pp = pm; pm = dynamic_cast<manager*>(pp); if (pm!= nullptr) pm->pr_department_list(cout); // upcast sker automatiskt Manager* -> * // downcast måste göras uttryckligen * -> Manager* // har vi en Manager? polymorfa pekare kan peka på objekt som motsvarande pekarens typ och dess subtyper upcast är en automatisk och är en säker typomvandling downcast måste göras uttryckligen och kan behöva kontrolleras innan vi opererar på objektet pr_department_list() är specifik för Manager och kan bara anropas via pekare av typ Manager* objekten i sig förändras e en Manager är alltid en Manager TDDC76 PoD OH Föreläsning C++ 120 Dynamisk typkontroll Ett sätt att ta reda på ett objekts typ är med typeid-uttryck inkludera <typeinfo> if (typeid(*pp) == typeid(manager))... kan användas för typnamn, objekt och alla slags uttryck ett typeid-uttryck returnerar ett objekt av typen type_info typkontroll kan göras genom att jämföra två type_info-objekt typeid-uttryck: typeid(*p) returnerar ett type_info-objekt för den typ av objekt som pekaren p pekar på typeid(r) returnerar ett type_info-objekt för den typ av objekt som referensen r refererar till typeid(t) returnerar ett type_info-objekt för typen T typeid(p) är vanligtvis ett misstag om p är en pekare ger type_info-objekt för pekartypen type_info-operationer: == testar likhet mellan två type_info-objekt typeid(*p) == typeid(t)!= testar olikhet mellan två type_info-objekt typeid(*p)!= typeid(t) name() returnerar typens namn i form av en C-sträng typeid(*p).name()

TDDC76 PoD OH Föreläsning C++ 121 Dynamisk typkontroll, forts. TDDC76 PoD OH Föreläsning C++ 122 Dynamisk typomvandling Typkontroll kan även göras med dynamic_cast. användning för polymorf pekare Manager* pm dynamic_cast<manager*>(pp) ; if (pm!= nullptr) pm->pr_department_list(cout); // typomvandla pp Med operatorn dynamic_cast kan man typomvandla polymorfa pekare och referenser: dynamic_cast<t*>(p) omvandlar pekaren p till pekare till T dynamic_cast<t&>(r) omvandlar referensen r till referens till T downcast från bastypspekare till subtypspekare eller från bastypsreferens till subtypsreferens upcast är en automatisk och säker typomvandling vid multipelt arv förekommer även crosscast dynamic_cast returnerar nullptr om pp e pekar på ett objekt av typen Manager eller en subtyp till Manager användning för polymorf referens rp antas ha typ & dynamic_cast<manager&>(rp).pr_department_list(cout); om e rp anger ett objekt av typen Manager, eller en subtyp till Manager, kastas undantaget bad_cast det finns inget tomma-referensen-värde en referens måste alltid vara bunden till ett objekt Observera: med typeid kan man bara testa mot en specifik typ T, e mot T och dess subtyper med dynamic_cast kan man testa om ett objektet är av typ T eller en subtyp till T dynamic_cast kräver dynamisk typinformation endast tillåten för polymorfa klasstyper typeid kan användas för alla typer, objekt och uttryck TDDC76 PoD OH Föreläsning C++ 123 Sammanfattning av konstruktion av polymorfa klasshierarkier polymorft beteende klasser måste vara polymorfa objekt måste refereras av pekare eller referens funktioner måste vara virtuella anrop av en funktion som e är virtuell binds alltid statiskt (vid kompileringen) den dynamiska typen typen för objektet avgör vilken överskuggning av en virtuell funktion som anropas dynamisk typomvandling krävs om en anropad funktion e tillhör typen för pekaren/referensen den statiska typen funktionsanrop kontrolleras statiskt inga exekveringsfel av sådan anledning rotklassen i en polymorf klasshierarki ska ha en virtuell destruktor en kompilatorgenererad destruktor är vanligtvis public och icke-virtuell, men om en basklass har en virtuell destruktor kommer en kompilatorgenerated subklassdestruktor också vara virtuell använd en virtuell medlemsfunktion som clone() för att kopiera polymorfa objekt kopieringskonstruktorn bör elimineras eller deklareras protected och då användas enbart ernt bruk kopieringstilldelningsoperatorn bör elimineras helt märk en klass final för att förbjuda subklassning märk en virtuell funktion override för att få kompilkatorn att kontrollera att överskuggning görs korrekt märk en virtuell funktion final för att förhindra överskuggning i eventuella subklasser