Operatorerna typeid och dynamic_cast mm - 1 Användning av typeid mm - 2 Vid dynamiskt bindning av funktioner vet man inte vilket objekt som funktionen binds till vid exekveringstillfället. Ofta saknar det betydelse men ibland kan det vara av intresse. T.ex om vi i laborationen med bankomaten hade velat skriva ut information om enbart lönekonton med hjälp av anrop till funktionen getinfo(), så hade det inte gått. Ett sätt lösa problemet detta är att förse alla kontobjekt med en medlemsvariabel som har ger information om vilken typ av konto som objektet är. Filen typeinfo.h måste inkluderas typeid typeid (*p) == typeid(c) typeid( r ) == typeid(c) p är en pekare, r en referens och C ett namn på en klass. Satsen blir sann om det utpekade (refererade) objektet tillhör klassen C typeid(*p).namn() typeid(r).namn() Ett annat sätt är att använda operatorn typeid för att testa vilket typ av objekt som kontot är Ger en textsträng med namnet på den typ det utpekade (refererade) objektet tillhör Ett tredje sätt är att försöka att tilldela en pekare av typen lönekonto adressen till kontoobjektet med hjälp av dynamic_cast 1
Användning av dynamic_cast mm - 3 Ett exempel med typeid och dynamic_cast mm - 4 Filen typeinfo.h måste inkluderas #include <typeinfo> using namespace std; dynamic_cast dynamic_cast<c *>(p) p är en pekare till ett objekt av klassen C eller en subklass till C, så ges som resultat p omvandlad till typen pekare till C annars 0 dynamic_cast<c &>(r) r är en referens till ett objekt av klassen C eller en subklass till C, så ges som resultat r omvandlad till typen referens till C annars genereras den exceptionella händelsen bad_cast //-Matsedel--------------------------------------------- void matsedel(restaurang *meny[], int antal) int i; Mat *matpek = 0; cout <<"MATSEDEL************************" << endl; for (i=0; i<antal; i++) if (matpek = dynamic_cast<mat *>(meny[i])) cout << typeid(*matpek).name() << endl; cout <<"********************************\n" << endl; //------------------------------------------------------ Exempel på utskrift MATSEDEL************************ 3Mat 9StektSill 4Palt 8FaluKorv ******************************** Dagens rätt är hyfsad. Nybakta Bullar är inte dumt. Korven är fantastisk! Palt smakar alltid Gott! Tack för maten! 2
Namnrymder mm - 5 Definition av namnrymder mm - 6 Namnrymder används för att hindra att namn som är globalt deklarerade att kollidera Till exempel om det i en inkluderingsfil förekommer följande deklaration: #ifndef _special_ #define _special_ const int size = 100; void swap(double &a, double &b)//...; #endif och denna fil inkluderas i nedanstående program så kommer detta att medföra en kollision mellan mellan de två konstanterna på grund av de har samma namn. #include <iostream.h> #include special.h const int size = 6; //Kommer att generera kompileringsfel double vek[size] = 0,1,2,3,4,5; En namnrymd är en konstruktion som till formen påminner om en klass Konstruktionen inleds med det reserverade ordet namespace följt av namnrymdens namn, därefter kommer ett block som kan innehålla ett antal godtyckliga deklarationer #ifndef _special_ #define _special_ namespace specialare const int size = 100; void swap(double &a, double &b) double temp = a; a = b; b = temp; #endif for (int i=0; i<size; i++) swap(vek[i], vek[size-i]); 3
Användning av namnrymder mm - 7 Exempel med användning av namnrymder mm - 8 Variabler och funktioners synlighet är normalt begränsade till namnrymdens block. Det finns tre olika sätt att få tillgång till något som är deklarerat i en namnrymd Explicit namngivning Ge det fullständiga namnet vid varje användning namnrymdensnamn::namn Användningsdeklaration Deklarera en viss identifierare på den aktuella platsen using namnrymdensnamn::namn; Användningsdirektiv Gör hela namnrymden öppen using namespace namnrymndensnamn; //- Exempel på explicit användning ---- #include <iostream.h> #include special.h const int size = 6; double vek[size] = 0,1,2,3,4,5; for (int i=0; i<size; i++) specialare::swap(vek[i], vek[size-i]); //- Exempel på användningsdeklaration ---- #include <iostream.h> #include special.h using specialare::swap; const int size = 6; double vek[size] = 0,1,2,3,4,5; for (int i=0; i<size; i++) swap(vek[i], vek[size-i]); 4
Klassen string mm - 9 Ett exempel med string mm - 10 Det finns en ny typ för att hantera strängar, standardtypen string För att använda denna typ måste man inkludera headerfilen string, utan.h! Några operationer i string. S och s2 är av typen string och x är antingen av typen string eller ett vanligt teckenfält (char - fält) ==================================================================== s = x tilldelning s==x s!=x s<x jämförelse s+x ger ny string sammansatt av s och x s[k] indexering utan indexkontroll s.at(k) indexering med indexkontroll s.substr(k,n) ger en del av s, början i k och längden n s.length() ger längden av s s += x lägger till x av s s.remove(k,n) tar bort n tecken ur s med början i pos k s.insert(k,s2,k2,n) skjuter in n tecken i s med början i k kopierar från k2 i s2 s.replace(k,n,x) ersätter n tecken i s med början i k med innehållet i x s.replace(k,n,s2,k2,n2) ersätter n tecken i s med början i k med n2 tecken ur s2 med början i k2 cout << s skriver ut s cin >> s läser in s, slutar vid första blanktecken getline(cin, s) läser in hel rad till s #include <string> #include <iostream> string firstname; string lastname; string adress; cout << "vad heter du? "; cin >> firstname >> lastname; cout << "Hej " << firstname << ' ' << lastname << endl; string namn = firstname; namn += " "; namn += lastname; cout << "Adress? "; cin >> ws; //Läser bort blanktecken getline(cin, adress); //Inläsning av en hel rad cout <<"\nnamn "<< namn<< " Adress " << adress << \n ; if (namn <= adress) cout << Ditt namn är inte större än din adress\n ; else cout << Din adress är mindre än ditt namn\n ; cout << Antal tecken i namnet <<namn.length() <<endl; Exempel på Utdata vad heter du? Kalle Kula Hej Kalle Kula Adress? Gostigen 3, Matstad Namn Kalle Kula Adress Gostigen 3, Matstad Din adress är mindre än ditt namn Antal tecken i namnet 10 tecken 5
Ett exempel med string och dess iterator mm - 11 Mera om STL, container klasser mm - 12 #include <string> #include <iostream> using namespace std; string namn; cout << "vad heter du? "; cin >> ws; getline(cin, namn); string::iterator i; for (i = namn.begin(); i!= namn.end(); i++) cout << *i; cout << endl; for (i = namn.begin(); i!= namn.end(); i++) if ( *i > 'Z' && *i!= ' ') *i -= 'a' - 'A'; for (i = namn.begin(); i!= namn.end(); i++) cout << *i; cout << endl; Exempel på Utdata vad heter du? Kalle Kula Kalle Kula KALLE KULA I Standard Template Library förekommer det många olika typer av datastrukturer Några av dessa är: Container klass Beskrivning ==================================================================== Sequence Containers vector Snabb insättning och radering i slutet av vektorn, direkt access till alla element deque list Dubbeländad kö. Snabb insättning och radering i början och slutet. Direkt access till alla element dubbellänkad lista, snabb insättning och radering av element i hela listan Associative Containers set snabb sökning, inga dubbletter tillåtna map ett till ett mappning, inga dubbletter tillåtna, snabb sökning med hjälp av söknyckel Container Adapters stack Sist in Först ut kö Först in Först ut priority_queue Högst priorerat element är alltid först ---------------------------------------------------------- Sequence och Associative Containers ingår i First-class containers 6
Mera om STL, medlemsfunktioner mm - 13 Mera om STL, typedef mm - 14 Några medlemsfunktioner som förekommer i containerklasserna är: Medlemsfunktion Beskrivning ==================================================================== Förekommer i samtliga containers empty Returnerar true om om det finns några element i kontainern i annat fall false max_size returnerar maximalt antal element som kan som kan förekomma i kontainern size Returnerar aktuellt antal element operator= Tilldelar en kontainer en annan kontainer Dessa funktioner förekommer ej i priority_queues operator< samtliga logiska operatorer är operator<= överlagrade vilket gör det möjligt att osv. jämföra en kontainer mot en annan Dessa funktioner förekommer endast i first-class containers begin returnerar en iterator som refererar till första elementet i containern end returnerar en iterator som refererar till första positionen efter sista elementet! rbegin Dessa båda funktioner är avsedda att rend användas tillsammans med en reverse_iterator erase Raderar ett eller flera element i kontainern clear Raderar samtliga element i kontainern ---------------------------------------------------------- Med hjälp av kontainerklassernas typdefinitioner är det möjligt att deklarera variabler som refererar eller pekar på element i kontainern: typedef Beskrivning ==================================================================== value_type Den typ som är lagrad i kontainern reference En referens till den typ av element som är lagrade const_reference En konstant deklarerad referens till elementen... pointer En pekare till elementen... iterator const_iterator reverse_iterator const_reverse_iterator difference_type En iterator som pekar på elementen En konstantdeklarerad iterator En iterator för omvänd traversering av elementen Den typ somerhålls när man subtraherar två iteratorer från varandra, som refererar till samma kontainer size_type Den typ somanvänds för att räkna element i kontainer och indexera sig igenom en sequence container ---------------------------------------------------------- 7
Ett exempel med vector mm - 15 Olika typer av iteratorer mm - 16 #include <iostream> #include <vector> #include <stdexcept> using namespace std; double tal =0.5; vector<double> datavek(5); vector<double>::size_type i; Utdata dataveks storlek: 5 dataveks storlek: 5 dataveks storlek: 10 datavek[6]: 6.5 data[6]: 6.5 input forward bidirectional output cout << Storlek: " << datavek.capacity() << endl; random access for (i=0; i<7; i++) datavek[i] = tal++; cout << Storlek: " << datavek.capacity() << endl; tal = 5.5; for (i=5; i<7; i++) datavek.push_back(tal++); cout << Storlek: " << datavek.capacity() << endl; cout << "datavek[6]: " << datavek[6] << endl; vector<double>::const_iterator data = datavek.begin(); cout << "data[6]: " << data[6] << endl; --------------------------------------------------- Secuence containers vector random access dequeue random access list bidirectional Associative containers set bidirectional map bidirectional Container adapters stack no iterators supported queue no iterators supported priority_queue no iterators supported 8
Typer av iteratorer och deras operatorer mm - 17 Typer av iteratorer och deras operatorer mm - 18 Fördefinerade typer Riktning Kapacitet ========================================================== iterator framåt läser/skriver const_iterator framåt läser reverse_iterator bakåt läser/skriver const_reverse_iterator bakåt läser ---------------------------------------------------------- Operationer =================================================== Alla iteratorer ++p, p++ Operatorer som enbart kan läsa *p, p=p1, p==p1, p!=p1 Operatorer som enbart kan skriva *p, p=p1 Operatorer som kan gå framåt Dessa operatorer har den funktionalitet som finns för de föregående typerna Operatorer som kan röra sig i båda riktningarna Dessa operatorer har den funktionalitet som finns för de föregående typerna samt --p, p-- Operatorer som kan röra sig i godtyckligt Dessa operatorer har den funktionalitet som finns för de föregående typerna samt p+=i, p-=i, p+i, p-i, p[i], p<=p1, p>p1, p>=p1 9
mm - 19 Containertypen map #include <map> #include <string> #include <iostream> using namespace std; Utskrift Namn: Anka Kajsa telefonnummer: 89732 Namn: Anka Kalle telefonnummer: 13131 Namn: Pigg Mimmi telefonnummer: 34578 Namn: Pigg Musse telefonnummer: 12345 Kalle Anka har telefonnummer: 13131 map<string, int> telefonlista; typedef map<string, int>::value_type post; telefonlista.insert(post("pigg Musse", 12345)); telefonlista.insert(post("anka Kalle", 13131)); telefonlista.insert(post("pigg Mimmi", 34578)); telefonlista.insert(post("anka Kajsa", 89732)); map<string, int>::const_iterator it; for (it=telefonlista.begin(); it!= telefonlista.end(); it++) cout << "Namn: " << (*it).first << "\ttelefonnummer: " << (*it).second << endl; if (telefonlista["anka Kalle"]) cout << "Kalle Anka har telefonnummer: " << telefonlista["anka Kalle"] << endl; 1