Programmering för nybörjare med C++ Nybörjarserie i programmering, Bd. I Täcker Programmering A, B och C av Förlag Taifun Alishenas Taifun Education
Bilden på omslaget visar den s.k. Diskos från Phaistos ett av arkeologins mest gåtfulla fynd eftersom den innehåller kod som ännu inte kunnat tolkas. Koden är ritad eller stämplad på en skiva av lera som har bränts. Två sådana unika skivor med olika texter skrivna i samma bildspråk hittades år 1908 i ruinerna efter den minoiska palatsanläggningen i staden Phaistos på Kreta. Denna antika stad förstördes år 1628 före Kristi födelse av en tsunamivåg som utlöstes av ett vulkanutbrott på ön Santorini norr om Kreta. Idag finns skivorna i museet av Heraklion på Kreta. Den över 3600 år gamla koden liknar hieroglyfer, s.k. piktogram som hittills inte hittats någon annanstans. De visar bl.a. människor, fåglar, fiskar, blommor, verktyg och andra objekt, alla ordnade i en spiralformig layout med raka streck som avskiljare mellan vissa otolkbara grupperingar kanske ord eller satser. Lyckligtvis är C++ kod långt ifrån så gåtfull. Den är inte bara möjlig att tolka både av människan och datorn utan går även att lära sig att skriva. Från båda utgår samma fascination som utstrålas av all symbolisk kod. Ännu roligare är dock att skapa kod som kan lösa praktiska problem med hjälp av datorn, ge bättre förståelse för hemligheterna bakom IT och förenkla människans arbete för att ha mer tid över för annat i livet. Det är nämligen just det programmering handlar om. Nybörjarserie i programmering: Bd. I Programmering för nybörjare med C++ Bd. II Grunderna i programmering med Java (se sid 394) Bd. III Programmering i.net-miljö med C# (se sid 395) Tacksam för kritik, synpunkter, påpekande av fel och förslag om korrektur eller förbättringar av innehåll eller form till c++@taifun.se Printed in Sweden Published by Taifun Education ISBN 9789197420402 www.taifun.se
Programmering för nybörjare med C++ En steg för steg-introduktion till programmeringsteknik Täcker Programmering A, B och C av Förlag Taifun Alishenas Taifun Education
Titel: Programmering för nybörjare med C++ Författare: Taifun Alishenas ISBN: 9789197420402 Copyright 2007 Taifun Education Box 604 182 16 Danderyd Tel: 08-792 36 28 Fax: 08-792 36 86 www.taifun.se Tryckeri: Täbykopia AB 1:a upplagan, 5:e tryckningen Mångfaldigande av innehållet i denna bok, helt eller delvis, är enligt Lagen om upphovsrätt förbjudet utan skriftligt medgivande av författaren. Förbudet inkluderar översättning, tryckning, stencilering, kopiering, lagring i elektroniska media, visning på bildskärm eller via projektor, bandinspelning osv. Dessa förbud gäller även för koden i alla programexempel som förekommer i boken. Alla produkter och företagsnamn nämnda i boken är varumärken för respektive ägare. 2
Vad boken handlar om Välkommen till programmeringens spännande värld! När man tröttnat på att bara använda program som andra skrivit, är det dags att börja programmera själv. Visst är det roligare att köra en bil än att bara åka med. Det är kreativiteten och det fria skapandet som lockar. Programmering kan vara en naturlig fortsättning för dig som hittills endast har mailat, surfat, spelat, skrivit eller räknat på datorn och nu vill veta mer om vad som händer bakom kulisserna i en dator. Man lär sig nämligen på ett helt nytt plan hur datorer fungerar när man programmerar själv. Dessutom kan man testa sina egna helt och hållet nya idéer. Programmering är ett av de mest spännande kapitlen i teknologihistorien. Inte bara därför att den har lagt grunden till den moderna IT-industrin. Den har också bidragit till att förverkliga den urgamla mänskliga drömmen om att med idéer kunna förenkla människans huvudsyssla, arbetet, för att ha mer tid över för annat i livet. Programmering är bokens huvudtema, ett tämligen allmänt ämne som praktiskt taget bara kan presenteras med hjälp av ett konkret språk. I denna bok används språket C++ som medel för att presentera programmering. Men medlet är av underordnad betydelse. Bokens mål är främst att förmedla tankesättet och tekniken att programmera, oberoende av språk. Har man en gång förstått de grundläggande principer som är gemensamma för alla programmeringsspråk, blir det närmast en teknikalitet att på egen hand lära sig ett nytt språk. Bokens egentliga ämne är alltså programmeringsteknik. Därför är bokens titel: Programmering för nybörjare med C++ dvs i första hand en steg för steg-introduktion till tekniken att programmera oberoende av språk. En lärobok om C++ själv som täcker hela språket med alla bibliotek osv. skulle fylla flera volymer. Här tas upp det som är mest relevant för programmering i alla moderna språk. Dessutom täcker upplägget det som brukar kallas för Programmering A, B och C. För en indelning av materialet i dessa tre kategorier se bokens innehållsförteckning. Böcker om programmering för nybörjare råder det ingen brist på, snarare tvärtom. Utbudet är så stort att man blir trött bara av att försöka hitta rätt bland alla braskande titlar. Några lovar att lära dig programmering på några veckor, 21 dagar eller 24 timmar! Så varför har jag valt att utöka denna redan digra samling med ännu en titel? Jag har många års erfarenhet av undervisning i programmering, matematik, numerisk analys och andra ämnen både på skol- och högskolenivå. I början av min bana antog jag att vissa begepp, sammanhang och förutsättningar var självklara, men den dagliga undervisningen fick mig snart på andra tankar. Mina elevers frågor, kritik och kommentarer fick mig att förstå var de begreppsmässiga luckorna i mina resonemang fanns. De var mina elever i programmering, matematik osv. men blev mina lärare i pedagogik. Som expert i ämnet har man för länge sedan glömt vilka svårigheter man själv upplevde som nybörjare. Ska man förklara stundtals ganska komplexa sammanhang krävs det naturligtvis ett intresse och en personlig fallenhet för ämnet, men det räcker inte. Det behövs också ett koncept om hur kunskapen ska förmedlas för att verkligen nå läsaren en aspekt som är primär i denna bok. 3
Röda trådens pedagogik Böcker i tekniska ämnen är ofta rena faktasamlingar vilket ofta är en konsekvens av ämnenas komplexitet. När de är skrivna för experter behöver det inte heller vara av nackdel. Men när nybörjare ska introduceras i ett ämne blir det problem om boken inte kombinerar kunskap med pedagogik. Då blir läroböcker ofta en ambitiös samling fakta i tegelstensformat som inte framhäver det väsentliga. För nybörjaren blir det allt svårare att hitta det väsentliga och följa en röd tråd. Oftast handlar det om elementär kunskap som experten tar för given, men blir den bristande länken i förståelsekedjan hos nybörjaren. Bokens ambition är att förverkliga den röda trådens pedagogik genom att stiga ned till nybörjarens kunskapsnivå och steg för steg bygga upp kunskapens hus av små lösa, logiskt härleddbara pusselbitar så att till slut allt faller på plats. Learning by doing teaching by example Programmering är i allra högsta grad ett praktiskt ämne. Därför är learning by doing det enda sättet att lära sig det. I detta avseende liknar programmering bilkörning. Du kommer aldrig att lära dig programmering enbart genom att läsa böcker. Men att bara pröva sig fram räcker inte heller. Ämnet är alltför omfattande. En handledning behövs, inte minst i början, som kombinerar sakkunskap med pedagogik, belyser det väsentliga och tillämpar ett helhetskoncept. Boken håller inga abstrakta lektioner utan använder teaching by example dvs exempelorienterad teoriundervisning i kombination med praktiska övningar: All teori, även de mest abstrakta begrepp åskådliggörs med praktiska programexempel. 100 fullständiga och testade program med körexempel förklaras i detalj. Ännu mer material presenteras i övningarna inklusive praktiska programmeringsprojekt. Gör så här: Skaffa dig tillgång till en dator. I boken ges anvisningar om hur man från Internet laddar ner och installerar gratisprogrammen Dev-C++ (sid 36) och Borland C++ Compiler (sid 4H44), hur man använder Visual C++ i Microsofts.NET-miljö (sid 5H39) samt hur man bygger en egen programutvecklingsmiljö för C++ med gratis programmet TextPad (sid 6H47). Gå igenom boken avsnitt för avsnitt, program för program. Kör bokens programexempel och experimentera med dem. Gör övningarna i slutet av varje kapitel. Genomför programmeringsprojekt som finns bland övningarna. Pröva dina idéer i egna program, återvänd till teorin, fördjupa förståelsen. All form av kritik, korrekturanmärkningar såväl som förslag till förbättringar av både form och innehåll tas tacksamt emot på adressen c++@taifun.se. Stockholm i december 2007 4 Taifun Alishenas Teknologie Doktor
Innehållsförteckning Programmering A Ämne Sida Program Kapitel 1 Introduktion till programmering 11 1.1 Vad är programmering? 12 1.2 Vad är en algoritm? 14 1.3 Olika sätt att beskriva en algoritm 17 1.4 Pseudokod och flödesplan 18 1.5 Vad är objektorienterad programmering? 23 Objekt, klass och metod 23 Objektorienteringens termer 25 1.6 Programmering: En kort historik 29 Övningar till kapitel 1 33 Kapitel 2 C++ miljöer 35 2.1 Dev-C++: En grafisk utvecklingsmiljö 36 2.2 Microsofts.NET-miljö Visual Studio 39 2.3 Borland: En textbaserad kompilator 44 2.4 En egen utvecklingsmiljö med TextPad 47 2.5 Att köra C++ i ett kommandofönster 52 Kapitel 3 Att komma igång med C++ 55 3.1 Reserverade ord 56 3.2 Hur får man in programmet i datorn? 58 3.3 Vårt första C++ program 61 01First 3.4 Utskrift till skärmen 65 02cout 3.5 Konkatenering 67 03Concat 68 04Figur Övningar till kapitel 3 69 Kapitel 4 Grundbegrepp i programmering 71 4.1 God programmeringsstil 72 4.2 Datatyper och variabler 74 05Datatyp 4.3 Definition och initiering av variabler 78 06Variabel Oinitierade och väl definierade variabler 81 07Oinitierad Definition och initiering i samma sats 82 08DefInit Objektorienterad initiering 83 09ObjInit Deklaration vs. definition 84 10Dekl/10Def 4.4 Överskrivning eller kan x = x + 1 vara sant? 87 11Overwrite 4.5 Inläsning av värden 89 12cin 4.6 Aritmetiska operatorer och uttryck 91 13TimSek Inmatning Bearbetning Utmatning 92 4.7 Ökningsoperatorn ++ 93 14PlusPlus 4.8 Sammansatt tilldelning 95 15SamTilld Övningar till kapitel 4 97 5
Ämne Sida Program Kapitel 5 Enkla datatyper 99 5.1 Datatypen char 100 16Kod 5.2 Explicit typkonvertering 102 17char2int 103 18int2char 5.3 ASCII-tabellen 104 19Ascii 5.4 Escapesekvenser 107 20Escape 5.5 De enkla datatypernas gränser 110 21Enkla Heltalstypernas gränser 112 22Limits Decimaltalstypernas noggrannhet 113 23Digits 5.6 Automatisk typkonvertering 115 vid tilldelning: Tilldelningsregeln 115 24TilldRegel 117 25Overflow vid aritmetiska operationer: int-regeln 118 26intRegel Befordringsregeln 119 27BefHeltal 121 28BefFlyttal Sammanfattning av kapitel 4 och 5 122 Övningar till kapitel 5 123 Kapitel 6 Kontrollstrukturer 125 6.1 Algoritmers byggstenar 126 6.2 Enkel selektion: if-satsen 127 29if Block 131 30ifBlock 6.3 Tvåvägsval: if-else-satsen 132 31ifelse 6.4 Flervägsval 135 Luriga else 135 32LurigaElse Nästlad if-else 137 33NestedIfElse switch-satsen 138 34switch switch med tomma case-satser 141 35switchOlik Kombination av switch och if-else 143 36GissaSwitch 6.5 Spagetti-programmering 144 37Spagetti 6.6 Efter-testad repetition: do-satsen 146 38GissaDo 6.7 För-testad repetition: while-satsen 149 39while Evighetsslinga 150 6.8 Bestämd repetition: for-satsen 151 Jämförelse mellan for och while 153 40forWhile ASCII-tabellen med for 154 41AsciiFor 6.9 Nästlade for-satser 157 42Stars Hantering av slumptal 158 43NestedFor Multiplikationstabellen 161 44MultNestFor Övningar till kapitel 6 (Projekt Labyrint I) 163 6
Programmering B Ämne Sida Program Kapitel 7 Logik för blivande programmerare 165 7.1 Sammansatta villkor 166 45Logik Logiska operatorer 167 46Kors De logiska operatorerna OCH och ELLER 168 47NegativtKors 7.2 Datatypen bool 173 48SannTab 7.3 NEGATION som logisk operator 175 49GissaLog Logiska uttryck 176 Test av lösenord med NEGATION 177 50PasswordNeg Datatypen string 177 7.4 Logiska lagar 178 51DeMorgan Test av lösenord med De Morgans lag 180 52PasswdMorgan 181 53PasswdMorgan Övningar till kapitel 7 (Projekt Labyrint II) 182 Kapitel 8 Funktioner 183 8.1 Vad är en funktion? 184 8.2 Definition och anrop av funktioner 187 54Funktion 8.3 Deklaration av funktioner 193 55Slumptal 8.4 Externlagrad funktion 196 56ExternFunk 197 56netto 8.5 Funktioner utan returvärde 199 57compare 200 57GissaVoid 201 slumptal 8.6 Lokala och globala variabler 202 58Global Blockstruktur 203 8.7 Överskuggning av variabler 207 59Scope Räckviddsoperatorn 209 8.8 Värdeanrop: Call by value 210 60CallByVal 8.9 Referenser 213 61Referens 8.10 Referensanrop: Call by reference 215 62platsbyte 216 62CallByRef 8.11 In- och utparametrar 218 63vaxel 220 63VaxelTest 8.12 Överlagring av funktioner 221 64potens 222 64Overload Övningar till kapitel 8 223 Kapitel 9 Array - en sammansatt datatyp 225 9.1 Vad är en array? 226 9.2 Definition och initiering av en array 228 65ArrayDef - Initieringslista 230 66ArrayInit 9.3 Stränghantering med array 233 67ArrayChar Nolltecknet 233 68Nolltecknet 7
Ämne Sida Program 9.4 Array som parameter i funktioner 240 69RefArray - Referensanrop med array 242 9.5 Sökning och sortering 244 slumparray - Slumptal i en array 245 70SearchTest 246 70search - Minimax-problemet 247 71minimax - Namngivna konstanter och skalbarhet 249 71MinimaxTest - Bubbelsortering 251 72bubbel 253 72BubbelTest 9.6 Kryptering av text 255 73KryptTextTest 256 73kryptText 9.7 Tvådimensionell array 258 74DoubleArray Övningar till kapitel 9 (Projekt Labyrint III, Master Mind) 262 Programmering C Kapitel 10 Filhantering 265 10.1 Att skriva till och läsa från filer 266 75WriteReadFile 10.2 Slumplösenord 270 76RandPasswTest 271 76randPassw 10.3 Kryptering av filer 273 77KryptFil 275 77kryptText2 276 77readShowFile 276 77writeFile 10.4 2D array som parameter i funktioner 277 78setTable Tabellhantering i filer 279 78writeTable 280 78readShowTable 281 78TableFile 281 78updateTable Övningar till kapitel 10 284 Kapitel 11 Pekare 285 11.1 Vad är en pekare? 286 11.2 Definition och initiering av en pekare 288 79Pekare 11.3 Adress- och värdeoperatorn 291 80Varde 11.4 Pekare och referens 297 81PekRef 11.5 Operatorn new 299 82new 11.6 Pekare och array 303 83PekArray Pekararitmetik 305 84PekAritm 11.7 Stränghantering med pekare 307 85Initialer 11.8 Referensanrop med pekare 311 86RefPek 11.9 Dynamisk minnesallokering 315 Datorns interna minneshantering 315 8
Ämne Sida Program Dynamisk array 317 87Dynamic Nollpekaren 319 11.10 Dynamisk filkryptering 321 88DynKryptFil Övningar till kapitel 11 324 Kapitel 12 Objektorienterad programmering 325 12.1 Vägen till objektorienterad programmering 326 89Allt_i_main 327 90Procedural Vår första klass 328 91Cirkel Test av klass 331 91ObjOrienterad Objekt och klass 332 12.2 Klass som datatyp 334 Deklaration av klass 335 92Anstalld Definition av objekt 337 92EgenDatatyp Åtkomst till objektets medlemmar 339 Punktnotation 340 12.3 Metoder 342 93Restid Objekt som parameter och returvärde 343 93RestidTest 12.4 Objektorienterad modellering 347 Implementation av modellen 350 94Tid Array av objekt 351 94TimAnstalld Referens till objekt 352 94Arbetstid 12.5 Inkapsling och klassens konstruktor 356 Åtkomstmodifieraren private 357 95Circle Klassens konstruktor 358 Default-konstruktorn 360 95Inkapsling Flera konstruktorer 362 96Circles 363 96Constructors 12.6 Åtkomstmetoder 365 97Emp 366 97Access 12.7 Komposition 367 98Date Komposition av klasser 367 98Employ Komposition av objekt 369 98Composition 12.8 Arv 372 99Person Arvrelationen 374 99Employee 375 99Inheritance 12.9 Polymorfism 376 100Konto Överskuggning av metoder 378 100MinimalKonto Åtkomstmodifieraren protected 379 100SkapaKonto Övningar till kapitel 12 (Projekt Automat) 382 Programförteckning 384 Sakregister 389 9
10
Kapitel 1 Introduktion till programmering 1.1 Vad är programmering? 12 1.2 Vad är en algoritm? 14 1.3 Olika sätt att beskriva en algoritm 17 1.4 Pseudokod och flödesplan 18 1.5 Vad är objektorienterad programmering? 23 Objekt, klass och metoder 23 Objektorienterad modellering 25 1.6 Programmering: En historik 23 Övningar till kapitel 1 33 11
1.1 Vad är programmering? Var och en har en intuitiv uppfattning i denna fråga. Ändå är det värt försöket att definiera programmering lite noggrannare. Det gäller att avgränsa ämnet och lokalisera det i förhållande till närbesläktade ämnen för att kunna sätta det i rätt sammanhang. Det blir lättare att följa bokens röda tråd, om man får en beskrivning av vad som väntar. Även om man intuitivt förstår vad programmering är, är det inte så enkelt att uttrycka det i ord. Då är det ofta enklare att börja med att ge negativa svar. Så låt oss börja med att diskutera vad programmering inte är för att steg för steg närma oss det positiva svaret *. På så sätt avgränser vi ämnet. Tre negativa svar 1. För det första hävdar jag att programmering inte är en konstart som måleri, musik, osv. För att syssla med konst behövs en viss begåvning. För programmering däremot räcker vanlig logik, någon speciell talang behövs inte. Därför kan i princip alla lära sig programmering. I princip eftersom det alltid finns undantag. Det gäller ju att kunna använda en teknisk apparat, inte att bygga den. Även här kan programmering jämföras med bilkörning. Att programmering inte är en konstart, utesluter inte att det i vissa fall kan finnas program som stiliserats till konstverk undantag som bekräftar regeln. Denna bok kommer att visa: I princip kan alla lära sig programmering. 2. För det andra hävdar jag att programmering inte är någon vetenskap. Det kanske förvånar mer än resonemanget om konst. Jo, det finns ett samband mellan programmering och vetenskap. Detta samband kan jämföras med relationen mellan bilkörning och maskinteknik eller med relationen mellan multiplikationstabellen och matematik. Visst är både maskinteknik och matematik vetenskap. Men ingen skulle därför hävda att även bilkörning och multiplikationstabellen är vetenskap. På liknande sätt är programmering relaterad till en vetenskap som kallas datalogi eller informatik, Computer Science på engelska. Programmering är endast en praktisk tillämpning av denna vetenskap. Medan datalogi kan beroende på upplägget ha en teoretisk prägel, är programmering i allra högsta grad ett praktiskt ämne. 3. För det tredje hävdar jag att programmering inte är ett självändamål. Programmering är ett medel, ett verktyg som tjänar ett högre syfte, nämligen att lösa ett problem med hjälp av datorn. Problemet kan vara vad som helst, bara man hittar ett sätt att behandla det på datorn. Lyckas man med det, har man datoriserat problemlösningen. Och detta kräver programmering. Så problemets lösning med hjälp av datorn är målet och programmering är medlet för att uppnå detta mål. Detta innebär inte att vi aldrig kommer att skriva program för programmeringens skull. Men detta sker endast i pedagogiskt eller experimentellt syfte. * Filosofen Spinoza anmärkte 1674 att varje definition är en negation. I och med man att säger vad någonting är, har man samtidigt sagt vad det inte är: Determinatio est negatio. I praktiken kan man närma sig definitionen genom att avgränsa det som ska definieras från allt annat. 12
Programmering som problemlösning En metod som exakt och entydigt beskriver ett problems lösning kallas algoritm. Väljer man programkod för att beskriva algoritmen, har man ett datorprogram. Sedan måste också viss information (data) läggas till för att lösa problemet, så man kan säga: Program = algoritm + data Det var Niklaus Wirth, skaparen av programspråket Pascal, som på 60-talet ställde upp denna definition. Data är information i organiserad, strukturerad form. Men vad exakt är en algoritm, och framför allt hur kan algoritmer beskrivas? Dessa frågor kommer vi att ägna resten av det här kapitlet till. Wirths definition återspeglar en algoritmorienterad syn på programmering som även kallas procedural (strukturerad) programmering. Slutsats: Förstå problemet, hitta och beskriv en lösningsalgoritm innan du börjar programmera. Att förstå problemet, att hitta och beskriva en algoritm är den svårare delen av uppgiften som oftast kräver mer tid och energi än själva programmeringen. Frågan är: Ingår verkligen alla dessa delar i programmerarens uppgift? Vad gäller att förstå problemet, måste i regel programmeraren vara förtrogen med problemställningen och ha en någorlunda god insikt i problemets viktigaste aspekter utan att därför vara expert i ämnet. Vad gäller att hitta en lösning, beror det på problemets karaktär och komplexitet. Ibland är en lösning känd och behöver bara studeras. I andra fall är problemet så komplext att endast experter i ämnet kan hitta en lösning då det krävs expertkunskaper, uppfinningsrikedom och/eller forskningsinsatser. Men det finns också enklare fall då programmeraren står ensam inför problemet och måste göra allt själv inklusive klara av problemlösningen. Så den här delen skulle kunna stå i parentes i slutsatsen ovan. Men att beskriva en lösningsalgoritm, steget innan kodningen, är nästan alltid programmerarens uppgift. Hur man gör det ska vi ägna oss åt i nästa avsnitt. Programmering som modellering En annan definition som kom på 80-talet och återspeglar den objektorienterade synen på programmering är: Program = Modell av verkligheten Om man i Program = algoritm + data lägger betoningen på data istället för på algoritmen och data inte längre betraktas som ett slags bihang till algoritmen utan som objekt eller en modell av verkligheten, kommer man till objektorienterad programmering som tas upp i bokens sista kapitel. Där kommer vi även att behandla objektorienterad modellering (sid 347). 13
1.2 Vad är en algoritm? Många tror att algoritmer bara har med matematik att göra. Så är inte fallet. Algoritmbegreppet är så allmänt att det kan användas för de flesta lösbara problem, inklusive matematiska. Det kan tillämpas på helt vardagliga problem, samtidigt som det är grunden för all programmering. Ett datorprogram är ingenting annat än en algoritm översatt till datorns språk. Men även följande vägbeskrivning till en kompis är ett fullgott exempel på en algoritm. Jämför den gärna med algoritmdefinitionen på sid 16. gå ut från ditt hus till vänster, fortsätt rakt fram, sväng till höger vid trafikljuset, sedan andra korsningen till vänster, där finns ett gult hus, i 26:an bor jag... En algoritm är alltså ett tillvägagångssätt vid problemlösning. En mer noggrann definition kommer vi att utveckla så småningom. Ett problem kan sakna lösning då kan det inte heller finnas någon algoritm. Om problemet är lösbart, kan det ha ingen, en eller flera algoritmer. Vi sysslar här endast med sådana problem som har minst en algoritm. Att algoritmer ofta förknippas med matematik har sina historiska skäl. Historiens första algoritm Ordet algoritm härstammar från namnet på en vetenskapsman från 800-talet som hette Al-Kharazmi. Namnet har sedan latiniserats och blivit algoritm. Han ställde upp historiens första algoritm genom att skriva en bok om Algebra med algoritmer för addition och multiplikation av heltal som används även idag. Men kunde man inte addera eller multiplicera heltal 800 år efter Kristi födelse? Jo, redan långt tidigare i Egypten, Indien, Persien och Grekland kunde man räkna med tal. Vad var i så fall Al-Kharazmis historiska prestation? Ja, det var inte att komma på hur man adderar eller multiplicerar heltal det var ju redan känt, utan hur man beskriver denna process. 1000 år mellan praktisk lösning och formell beskrivning Det är anmärkningsvärt att beskrivningen av hur man räknar med heltal kom till mer än 1000 år efter den praktiska lösningen. Orsaken är att den korrekta, allmänna beskrivningen som ska hålla i alla tänkbara situationer, är mycket svårare att åstadkomma än den faktiska lösningen av ett eller en klass av problem. Att själv gå en väg som man känner till är enklare än att formulera en korrekt vägbeskrivning. Anledningen är att algoritmer är generella till sin natur, och just det är tjusningen: Att försöka beskriva dem så att de håller i alla situationer. Och detta gäller även idag: Program det moderna sättet att beskriva algoritmer måste fungera under alla omständigheter och ska helst aldrig krascha. Dessvärre vet vi ju att så inte är fallet. En av utmaningarna inom programmering ligger i att skriva program som fungerar i alla situationer. Det vi kan lära oss av det 1000-åriga glappet mellan praktisk lösning och formell beskrivning är: Satsa tid och energi på att först analysera det problem du vill att ett program ska lösa och på att beskriva lösningen av problemet så generellt som möjligt. Prefixet Al kan tyda på att han var arab, men namnet Kharazmi avslöjar att han är född i Kharazm, en antik ort i dagens Iran som på den tiden var ockuperat av araberna. 14
Exempel på algoritmer I vardagen använder vi algoritmer hela tiden, om än omedvetet. Här några exempel: Matrecept vars användning kan jämföras med programkörning på datorn: Råvaror (indata) Kök Maträtt (utdata) (dator) Matrecept (algoritm/program) Matrecept skrivs fortfarande med vanligt språk men man kan konstatera att det finns en viss stil som är typisk för alla matrecept. IKEA:s monteringsanvisningar för att sätta ihop delarna till en möbel. Här används en kombination av text och grafik som är mycket effektiv. Grafiken förenklar algoritmen avsevärt. En bild säger mer än tusen ord. På köpet får man en slags internationalisering, ett oberoende av det lokala språket, vilket gör att algoritmen förstås över hela världen. Bruksanvisningar av alla slag är exempel på algoritmer, även om många av dem i praktiken är värdelösa. Men det finns dåliga algoritmer på andra områden också. Manualer för datorprogram som visar hur ett program ska användas. Konstruktionsritningar som ingenjörer gör för att en viss produkt ska kunna tillverkas i fabrik. En arkitektritning av ett hus är ett specialfall av det. Här har grafiken tagit över helt och hållet. Partiturer: Noter i musik som används för att spela ett musikstycke och som omfattar noggranna anvisningar om hur en hel orkester ska spela. Ett speciellt språk används som varken består av text eller grafik, utan snarare av symboler längs en tidslinje. Spelregler är snarare ett negativt exempel: De talar mest om vad man inte får göra och lämnar ett stort utrymme för hur man får spela inom reglernas ram. Därför finns två skilda problemställningar. Den ena är: Hur får jag spela? Spelregler ger delvis (negativa) svar på det. En helt annan problemställning är: Hur vinner jag spelet? Spelteori som involverar sannolikhetslära behandlar denna fråga. I spelteori brukar man tala om strategier snarare än algoritmer. Här befinner vi oss i ett gränsområde där problem inte alltid har en lösning eller saknar algoritm. I fortsättningen kommer vi att undvika sådana frågeställningar. Vi betraktar endast problem som är lösbara och har minst en algoritm. Exemplet belyser dock en viktig aspekt: Inte bara vägen till lösning måste beskrivas. Först måste problemställningen vara klart och exakt formulerad så att man kan avgöra om det finns en entydig lösning och minst en algoritm. 15
Definition av algoritm Låt oss titta på vad som är gemensamt för exemplen ovan (utom spelreglerna). Vilka typiska faktorer förekommer i alla exempel? För det första består de alla av en rad anvisningar om vad som ska göras för att lösa det givna problemet. Frågan är: Ska man tillåta alla slags anvisningar? Om de leder till problemets lösning, varför inte? Men leder alla slags anvisningar till lösningen? T.ex. anvisningen Bygg ett hus! är helt värdelös. Ingen kan bygga ett hus med bara denna anvisning. Problemet är ju just hur man bygger huset. Anvisningarna måste vara mycket enklare och mer detaljerade. Vem som helst ska kunna utföra dem. Sådana anvisningar kallas elementära instruktioner. Bara sådana kan tillåtas i en algoritm om de ska leda till problemets lösning. För det andra. Undersöker man de ovannämnda exemplens innehåll kan man konstatera att anvisningarna måste utföras i en viss ordning. Det går inte att kasta om ordningen. Man inser redan vid receptexemplet att man först måste knåda degen och sedan ställa in den i ugnen, inte vice versa. Vid partiturexemplet är ju ordningen helt avgörande. Och så är det i alla algoritmer. Ordningsföljden för de elementära instruktionerna måste finnas med i algoritmen. Självklart måste en algoritm också ange när instruktionerna ska upphöra. Om vi sammanfattar kommer vi till följande definition av algoritm: En algoritm är en följd av precisa anvisningar, s.k. elementära instruktioner, som löser ett givet problem samt en anvisning om i vilken ordning dessa skall utföras. Dessutom måste en algoritm alltid ha ett exakt avslutningskriterium. Denna definition är fortfarande ganska intuitiv, men den räcker för vårt ändamål. Mer formella definitioner finns i den vetenskapliga litteraturen som tar hänsyn till att antalet elementära instruktioner måste vara ändligt och att algoritmen ska kunna utföras i ändlig tid. Vi tar dessa förutsättningar för givna. Men avslutningskriteriet är avgörande: Ett tillvägagångssätt måste ha ett exakt avslutningskriterium annars är det ofullständigt och utgör ingen algoritm. Av stor betydelse för datoriseringen är att algoritmen måste vara tolkningsbar på ett enda sätt. Det får inte finnas tvetydigheter i formuleringen. Datorn kan ju bara tolka våra anvisningar på ett enda sätt. Svårigheten ligger alltså i algoritmens beskrivning, vilket är en god illustration till det 1000-åriga glappet mellan praktisk lösning och formell beskrivning som vi nämnde på sid 14. Som redan sagts, är det i regel svårare att beskriva en algoritm än att lösa ett specifikt problem i en specifik situation. Algoritmer är generella till sin natur och måste hålla i alla situationer. Och därmed har vi kommit fram till nästa avsnitts diskussion: Hur beskriver man en algoritm bäst? Vi ska nu gå igenom de hjälpmedel man kan använda för att formulera algoritmer så att de blir tolkningsbara endast på ett sätt men samtidigt behåller sin generella karaktär. 16
1.3 Olika sätt att beskriva en algoritm Vanligt språk är, som vägbeskrivningen till en kompis på sid 14 visade, ett sätt att beskriva algoritmer. Största fördelen med det är att alla som kan språket direkt förstår algoritmen utan att behöva lära sig något nytt. Nackdelen är att det ofta kan tolkas på olika sätt. Och tur är det! Annars skulle man ju t.ex. inte kunna skriva en dikt eller njuta av den. Men just i samband med algoritmer då man eftersträvar entydighet, är möjligheten till olika tolkningar en nackdel. Pseudokod är en hybrid (blandning) mellan vanligt språk och formaliserad kod, ett försök att minska det vanliga språkets tvetydighet genom att införa vissa strukturer och t.o.m. grafiska stilmedel i layouten. Allt som på ett entydigt sätt beskriver en algoritm, även en matematisk formel, kan användas som pseudokod. I nästa avsnitt tar vi upp ett exempel på pseudokod med vanligt språk kombinerad med generella kontrollstrukturer (sid 20) som förekommer i alla algoritmer. På så sätt uppnår det vanliga språket en högre grad av entydighet, noggrannhet och struktur. Flödesplan eller flödesschema är en variant av IKEA:s monteringsanvisningar som kombinerar text och grafik med en klar dominans mot det senare. Man använder sig av geometriska figurer som symboliserar algoritmens byggstenar och av pilar som visar flödet i algoritmen och definierar instruktionernas ordning. Med dessa få stilmedel uppnår man en hög noggrannhet i beskrivningen, eliminerar tvetydigheter och åskådliggör algoritmens logiska struktur. Det tänkta händelseförloppet syns tydligt. I det avseendet är flödesplan överlägset både vanligt språk och pseudokod. Flödesplanssymbolik är ett utmärkt medel som lämpar sig inte bara för beskrivning av fullständiga algoritmer, utan också för att åskådliggöra logiken hos mindre, men kritiska delar av ett program. Vi kommer att använda oss av detta medel i hela boken. Programkod är den variant av algoritmbeskrivning som används för att låta en dator utföra algoritmen. Därför måste den kunna tolkas av datorn. Programkoden översätts till ett språk, kallat maskinkod som datorns processor förstår. Programkoden däremot även kallad källkod är skriven i något programmeringsspråk som man måste lära sig. Medan källkod förstås av människan, men inte av datorn, förstås maskinkod av datorn, men inte av människan. Andra sätt att beskriva algoritmer finns också. Inget av dem har lyckats etablera sig som standard. Många av de traditionella sätten kan betecknas med det samlande namnet strukturdiagram. Andra använder Mind Maps eller beslutstabeller. Mest känt är dock UML = Unified Modeling Language som är ett språk för objektorienterad design, dvs ett sätt att planera, utveckla och visa strukturen hos avancerade objektorienterade system. Idag används UML för att lägga upp och modellera stora programmeringsprojekt. UML kräver goda kunskaper i objektorienterad programmering som tas upp i bokens sista kapitel. Där kommer vi även att behandla objektorienterad modellering (sid 347). Här ska vi nu utveckla de enklare struktureringsverktygen pseudokod och flödesplan. 17
1.4 Pseudokod och flödesplan Låt oss som exempel ta följande beskrivning på ren svenska av en vardaglig syssla: K går upp kl. 6 och duschar tills kroppen känns fräsch. Sedan torkar K sig, tar på sig kläderna och äter frukost. Vid frukosten lyssnar K på radions trafikinformation. Om det är mycket biltrafik, går K ut, väntar tills ingen bil kommer, går över gatan och tar bussen till jobbet. Annars tar K bilen till jobbet. Det är en beskrivning av en algoritm, låt oss kalla den för Morgonsyssla, som använder sig av det vanliga språket. Egentligen kan den knappast misstolkas när den används med lite sunt förnuft. Ändå vill vi skriva om den, först som pseudokod och sedan som flödesplan för att öva de nya begreppen. Som vi ska se kommer detta att leda till en precisering av algoritmen. Pseudokod till algoritmen Morgonsyssla Gå upp kl. 6 Duscha TILLS kroppen känns fräsch Torka och ta på dig kläderna Ät frukost och lyssna på radio OM det är mycket biltrafik gå ut vänta TILLS ingen bil kommer gå över gatan och ta bussen till jobbet ANNARS ta bilen till jobbet Låt oss analysera denna pseudokod lite närmare. Vad skiljer den från vanligt språk? Vi har gett texten en ny form utan att ändra innehållet. Nya regler för formen har införts: För det första finns det varken punkter eller kommatecken mellan satserna. För att skilja dem åt, börjar istället varje sats på en ny rad. För det andra innehåller varje sats endast en elementär instruktion. För det tredje är vissa rader indragna vilket visar att instruktionerna på dessa rader, är underordnade andra instruktioner dvs är delar av dem. Så kan vi skilja mellan huvud- och underinstruktioner. Algoritmen har 5 huvudinstruktioner: I. Gå upp kl. 6 II. Duscha TILLS kroppen känns fräsch III. Torka och ta på kläderna IV. Ät frukost och lyssna på radio V. OM... ANNARS... Att vi räknar OM-ANNARS-satsen som en instruktion, beror på att de hör ihop och bildar ett par: ANNARS skulle förlora sin mening om det skiljdes från OM. Sedan har algoritmen 18
4 underinstruktioner, 3 under OM och 1 under ANNARS. De är alla indragna. Underinstruktionen gå ut skulle kunna betecknas med V.a då den tillhör huvudinstruktion V. Undersinstruktionen vänta TILLS ingen bil kommer skulle i så fall få beteckningen V.b. Undersinstruktionen gå över gatan och ta bussen till jobbet blir V.c och ta bilen till jobbet V.d. Hela algoritmen består av 5 huvud- och 4 underinstruktioner. Villkor Låt oss nu fördjupa analysen av pseudokoden och ta itu med de lite mer invecklade instruktionerna, t.ex. med II:an: Duscha TILLS kroppen känns fräsch Hur länge står K under duschen? Innebörden av TILLS säger att detta avgörs av hur länge kroppen känns ofräsch. Dvs K frågar sig ständigt, kanske omedvetet: känns kroppen fräsch, ja eller nej? Om nej, fortsätt duscha! Om ja, sluta! Detta händer kontinuerligt under duschandet. Hur många gånger, är inte bestämt, utan avgörs av K:s subjektiva svar på frågan. Menar K att kroppen förblir ofräsch trots duschandet, då ska K enligt algoritmen fortsätta att duscha i all evighet! I pseudokoden formuleras känns kroppen fräsch däremot inte som fråga, utan som ett villkor som ingår i TILLS-satsen, ett villkor för att fortsätta eller avsluta duschandet. Villkoret testas gång på gång: är det sant, ska K avsluta duschen. Är villkoret falskt, ska K duscha vidare. Valet avgörs av villkorets sanningsvärde, dvs om det är sant eller falskt. Ett villkor kan endast vara sant eller falskt. På så sätt skiljer sig ett villkor från en instruktion. En instruktion utförs, ett villkor testas. Testet avgör om en instruktion ska utföras eller inte. Det finns flera villkor i pseudokoden, utmärkta i kursiv stil. Nästa villkor förekommer i huvudinstruktion V: OM det är mycket biltrafik... ANNARS ta bilen till jobbet Den kursiva texten är ett villkor som avgör om K ska gå över gatan och ta bussen eller ta bilen till jobbet. Är villkoret sant dvs om det är mycket trafik, då ska K gå över gatan och ta bussen. Är villkoret falskt dvs om det inte är så mycket trafik, ska K ta bilen till jobbet. Men till skillnad från TILLS-satsen testas villkoret här endast en gång, beroende på den annorlunda innebörden av OM. Ett tredje villkor finns i underinstruktionen V.b: vänta TILLS ingen bil kommer Logiken avgörs igen av TILLS dvs K ska vänta så länge det kommer någon bil. När det inte längre kommer någon bil, ska K sluta vänta. K ställer sig alltså gång på gång frågan: kommer någon bil, ja eller nej? Om ja, fortsätt vänta! Om nej, sluta vänta! Kommer det bilar hela tiden, då ska K enligt algoritmen vänta i all evighet! 19
Kontrollstrukturer Har vi därmed kartlagt pseudokoden till algoritmen Morgonsyssla? Nästan! Vi har identifierat instruktioner (normal stil) och villkor (kursiv stil). Vi nämnde även orden TILLS och OM-ANNARS (fet, versal stil), men vi har ännu inte identifierat dessa ord. De är ju varken instruktioner eller villkor, så vad är de? Låt oss för ett ögonblick glömma algoritmen Morgonsyssla och tänka oss en helt annan algoritm som ska lösa ett helt annat problem. Vilka ord skulle även förekomma i den nya algoritmen? Säkert ingen K *, inget jobb, ingen dusch, ingen bil, ingen.... Men just det! Orden TILLS och OM-ANNARS kan finnas i den nya algoritmen också. Och de kan förekomma inte bara i den av oss tänkta algoritmen utan i alla algoritmer. De är nyckelord och fungerar som algoritmens byggstenar. I programmering kallas de för kontrollstrukturer eftersom de är generella strukturer som styr och kontrollerar hela algoritmen och förekommer i alla algoritmer. Ja, alla algoritmer är uppbyggda av dessa kontrollstrukturer. Behärskar man dem, har man tagit ett stort steg mot förståelse av algoritmer och därmed förståelse för programmering. Vi kommer i kapitel 6 (sid 126) att detaljerat behandla kontrollstrukturer i C++. Nu ska vi titta på flödesplan, ett annat lite roligare sätt att beskriva algoritmer. Sedan ska vi rita algoritmen Morgonsyssla som flödesplan. Flödesplan För att kunna rita en flödesplan som kombinerar text och grafik med en klar dominans mot det senare, måste vi införa några grafiska symboler: Algoritmens start och slut ritas med en oval. En instruktion ritas som rektangel. Instruktionens text skrivs in i rektangeln. Ett villkor ritas som romb. Villkoret skrivs in i romben och kan även formuleras som fråga. Start/Slut Instruktion 1 Villkor Flödet (ordningen) i algoritmen visas med pilar. Det finns fler symboler, men vi kommer bara att använda oss av de ovan redovisade när vi på nästa sida presenterar flödesplanen till algoritmen Morgonsyssla som ska bli en exakt översättning av den algoritm som vi ursprungligen formulerade (sid 18) först på vanligt språk och sedan som pseudokod. Precis som vi gav texten i vanligt språk en ny form utan att ändra innehållet när vi skrev om den till pseudokod, ska även vid översättning till flödesplan ytterligare en ny form ges till algoritmen utan att ändra innehållet, framför allt inte den logiska innebörden. Flödesplanens fördel kan beskrivas med ordspråket En bild säger mer än tusen ord. * Paralleller med Franz Kafkas romanfigur Herr K. är rent slumpmässiga! Algoritmens K kan stå för vem som helst. Personen i fråga är irrelevant. I flödesplanen förekommer inte ens K, vilket visar att det inte handlar om personen utan om problemet Att ta sig till jobbet. Vi har här att göra med problemlösning (procedural), inte med modellering av verkligheten (objektorienterad). 20
Flödesplan till algoritmen Morgonsyssla Start Gå upp kl. 6 Duscha Loop* Kroppen fräsch? nej ja Torka och ta på sig kläderna Äta frukost & lyssna på radio Gå ut ja Mycket biltrafik? nej Ta bilen Vänta Loop* Kommer någon bil? ja nej Gå över gatan & ta bussen Slut Loop = slinga på svenska, här: upprepningsslinga med inbyggt villkor som testas gång på gång. 21
När vi sa att Morgonsyssla-algoritmens flödesplan ska bli en exakt översättning av den algoritm som vi ursprungligen formulerade på sid 18 menade vi förstås förstås den logiska likheten, inte den språkliga. T.ex. står i pseudokoden vänta TILLS ingen bil kommer medan i flödesplanen står Kommer någon bil? och flödesplanen svarar på denna fråga: om ja, vänta vilket innebär vänta SÅ LÄNGE det kommer någon bil. Formuleringen är logiskt likvärdig med vänta TILLS ingen bil kommer. Hade vi formulerat frågan negativt Kommer ingen bil? hade det lett till dubbel negation vid svaret nej, vilket försvårar förståelsen. För att förenkla har frågan i flödesplanen formulerats positivt. Undersök själv om det finns flera exempel på språklig olikhet men logisk likhet mellan den ursprungliga texten och flödesplanen. Det är en utmärkt övning att kontrollera om vi på vägen från vanligt språk till flödesplan verkligen inte ändrat algoritmens innehåll. Om man jämför pseudokoden med flödesplanen till Morgonsyssla kan man konstatera att det är avsevärt enklare att få en snabb överblick över algoritmen när man tittar på flödesplanen. Frågan uppstår varför man i så fall överhuvudtaget ska syssla med pseudokod. Svaret är att det är programkod som vi slutligen ska skriva, och programkod liknar pseudokod mer än flödesplaner. Vi kan inte mata datorn med grafik som är huvudingrediensen i flödesplaner. Pseudokodens värde ligger i närheten till programkod. Dessutom är den oberoende av programmeringsspråk. Flödesplan däremot är ett utmärkt hjälpmedel som kan användas innan man skriver programkod för att strukturera sina tankar om ett problems lösning som ska tas fram med ett datorprogram. Även detta verktyg är helt oberoende av programmeringsspråk. Är problemet enkelt eller om en klar struktur för lösningen redan finns, behövs ingen flödesplan. Växer problemets komplexitet rekommenderas en flödesplan kombinerad med pseudokod. 22
1.5 Vad är objektorienterad programmering? Här ska vi fortsätta besvara frågan Vad är programmering? som vi tog upp i början av detta kapitel och komplettera svaret ur en objektorienterad synvinkel. Då hade vi definierat programmering som problemlösning och citerat Niklaus Wirth som på 60-talet formulerade den procedurala synen på programmering med definitionen Program = algoritm + data (sid 13). En annan definition som kom upp på 80-talet och återspeglar den objektorienterade synen på programmering är: Program = Modell av verkligheten Om man i formeln Program = algoritm + data lägger betoningen på data istället för på algoritmen och inte längre betraktar data som ett slags bihang till algoritmen utan som objekt kommer man till objektorienterad programmering. Denna nya programmeringsfilosofi kommer att behandlas i boken, eftersom C++ är ett objektorienterat språk. Det som i programmeringshistorien gjorde att man behövde objektorienterad programmering var den växande komplexiteten hos program under 70-talet. Programmens storlek var avgörande för den växande komplexiteten. Man insåg att det inte längre räckte till att skriva och testa program som fungerade just då. Det var nödvändigt att med rimliga kostnader kunna även underhålla stora program, förnya och vidareutveckla dem så att de fungerade även i flera år och att de framför allt kunde anpassas till nyuppkomna situationer utan oöverkomliga svårigheter. Det i sin tur krävde att man redan i designstadiet behövde ett annorlunda upplägg. Fokuset förskjöts från problemlösning till modellering av verkligheten. Objektorienterad design (UML) kom in i bilden. Allt detta var endast med procedural programmering inte längre möjligt. Ett s.k. paradigmskifte hade blivit nödvändigt, dvs en ändring av helhetssynen på programmering. Objektorienterad programmering syftar åt att efterlikna verkligheten. Man vill avbilda den reala världen åtminstone den del som tillåter datorisering och konstruera en modell av den i sina datorprogram för att kunna simulera verkligheten genom att testa modellen. För att undvika filosofiska diskussioner kan vi anta att den reala världen består kort sagt av objekt. Världen kring oss är full med sådana objekt: Människor, byggnader, bilar, tåg, flygplan, träd, möbler, böcker, butiker, skolor, bibliotek, kontor, anställda, kunder, varor, fakturor, order, bokningar, kurser osv. Objekten kan vara verkliga eller virtuella. Ett datorprogram försöker att beskriva dessa objekt. Låt oss precisera detta: Objekt, klass och metod Det är tre centrala begrepp inom objektorienterad programmering. Ett objekt har vissa egenskaper. Generellt kan man säga att ett objekt är summan av alla sina egenskaper. Ett annat ord för egenskap är attribut. Ett objekt består av alla sina attribut. Attributen tillhör objektet. T.ex. har objektet bil som attribut fabrikat, modell, färg, årsmodell, antal körda mil, antal hästkrafter, maximala hastigheten, antal och storlek på cylindrar i motorn osv. Alla dessa data ger svar på frågan Vad är det för bil?. Men bilden vore ofullständig om vi nöjde oss med dessa intressanta, men statiska data. Vi vill också veta vad man kan göra 23
med bilen. Ett objekt kan i regel även utföra vissa aktioner eller operationer. I den objektorienterade programmeringens terminologi kallas de för metoder. En annan beteckning är funktioner. Skillnaden mellan dessa två begrepp är att funktioner är fristående, medan metoder är kopplade till klasser och objekt. Att relatera en aktion till ett objekt eller se den som fristående är två olika syn på saker och ting. Typiska metoder för en bil är t.ex. att köra fram, att backa, att accelerera, att bromsa, att parkera, att byta olja osv. Den fullständiga definitionen på en bil som objekt vore alltså att ange både dess attribut och metoder. Bilfabrikanten måste förse bilen med alla dessa färdigheter för att kunna sälja den. Därför går man i bilfabriken efter en plan när man tillverkar bilen. I den objektorienterade programmeringens terminologi kallas denna plan för bilens klass. När vi skriver ett program måste vi först formulera klassen Bil för att sedan kunna skapa objekt av den. Klassen skrivs bara en gång, medan objekt kan skapas enligt klassens beskrivning i obegränsat antal. I klassen måste vi ta upp alla attribut och metoder som är relevanta eller av någon anledning önskvärda för en bil. Den praktiska användningen avgör från fall till fall vad som är relevant eller önskvärt. Vad är skillnaden mellan objekt och klass? Om vi byter ut bilar mot pepparkakor kan man säga att pepparkaksformen är klassen och själva pepparkakorna är objekten. Klassen är alltså en slags mall, en förskrift för produktion av objekt: En enda pepparkaksform kan producera tusentals pepparkaksgubbar. Gubbarna kan skiljas från varandra i vissa detaljer, t.ex. materialet, smaken osv. Man kan t.o.m. måla dem i olika färger eller modifiera på annat sätt efteråt. De förblir pepparkaksgubbar av den ursprungliga formen. I formen ingår det som är gemensamt hos alla pepparkaksgubbar. Man har, när man byggde formen, bortsett från oväsentliga skillnader och tagit hänsyn endast till det väsentliga, det gemensamma hos alla pepparkakor. Att bortse från skillnader och att bibehålla det gemensamma hos olika verkliga objekt, kallas abstraktion (abstrahera, på latin: att ta bort, att dra av). Man tar bort allt som skiljer saker och ting av samma kategori eller typ och kommer på det viset till själva kategorin. Abstraktion leder till begreppsbildning, till klassificering eller kategorisering av den reala världen. Ett växande barn går igenom samma abstraktionsprocess, ser först sina föräldrar (objekt), abstraherar sedan via erfarenhet så småningom till begreppet människa (klassen) och inser att sina föräldrar är två konkreta exemplar av den abstrakta klassen människa. Så gör barnet med alla saker och ting omkring sig och lär sig vuxenvärldens begreppsapparat. Det abstrakta begreppet penna (klassen) t.ex. bildas efter att man sett hundratals verkliga pennor (objekt). Objektorienterad programmering återspeglar denna naturliga tankeprocess från det konkreta till det abstrakta, från objekt till klass. Anrop av metoder med punktnotation Vad gör man med metoder? Det finns två steg i hantering av metoder: Först definierar dvs skapar man dem i en klass. Sedan anropar dvs aktiverar man dem i ett objekt av denna klass. Ofta är det första steget redan genomfört av andra, så vi behöver bara anropa en redan fördefinierad metod. I klassen Bil t.ex. är metoderna att köra fram, att backa, att accelerera, att bromsa osv. definierade i huvuden på bilkonstruktörerna och i deras konstruktionsritningar och dokumentationer. Sedan har man tillverkat massor med objekt av klassen Bil i fabriken och byggt in dessa metoder i alla bilar. Vi behöver bara 24
anropa dem i den bil vi kör. Den bil vi kör är ett specifikt objekt av klassen Bil. Låt oss kalla det för minvolvo. Objektet minvolvo har ett antal attribut som t.ex. fabrikat, modell, färg, årsmodell osv., men också ett antal metoder, bl.a. metoden kör(). Parenteserna i metodens namn brukar man skriva för att karakterisera kör() som en metod och skilja den från klassens attribut. I C++ skriver man ett anrop av metoden kör() så här: minvolvo.kör(); Observera att före punkten står ett objekt, inte klassen. Det är ju den specifika bil som jag använder just nu som ska köras. Först efter punkten står själva anropet av metoden kör(). Det här sättet att skriva kallas punktnotation. Metoder måste alltid anropas med punktnotation, vilket har sin grund i att de endast är definierade i klasser, så att de endast existerar i objekt av en klass. Till skillnad från funktioner som är fristående, kan metoder varken definieras utanför klasser eller anropas utanför objekt. I C++ finns både funktioner och metoder. Om vi bortser från bilexemplet kan det i andra sammanhang även förekomma en klass (istället för objekt) före punkten i anropet av en metod. I så fall är metoden definierad i klassen på ett speciellt sätt nämligen som en statisk metod, vilket tas upp när vi behandlar metoder i detalj. En annan variant av metoden kör() kan anropas på fäljande sätt: minvolvo.kör(40); Det kan t.ex. betyda: Kör bilen med hastigheten 40 km/h. Värdet 40 kallas då en parameter som skickas till metoden när den anropas. I så fall måste även metoden kör() vara definierad så att den har beredskapen att ta emot denna parameter. Så det kan inte vara samma metod som anropades utan parameter. Det måste vara en annan variant av den, exakt talat en annan metod med samma namn. Konceptet kallas överlagring av metoder och innebär två eller flera metoder med samma namn, men olika parametrar. Objektorienteringens termer Låt oss återuppta exemplet Morgonsyssla som vi diskuterade i de förra avsnitten och försöka att integrera det i den nya terminologin. Algoritmen Morgonsyssla är ett typiskt fall av problemlösning: Den löser problemet om hur K. tar sig till jobbet. Tillvägagångssättet och framför allt hur vi beskriver det, är föremål för algoritmer. Men vem eller vilka gör det, dvs objekt som är involverade i algoritmen och hur man beskriver objekt, är en annan aspekt på saken. Objektorienterad programmering prioriterar objektaspekten framför algoritmaspekten. I det här fallet är objektet K. som utför algoritmens instruktioner för att ta sig till jobbet. Den primära frågan är nu: Vem är K. eller hur kan K. beskrivas? Hur han gör för att ta sig till jobbet kommer att ingå som en del i denna beskrivning. K. kan vara en anställd vilket förresten skulle förklara varför han tar sig till jobbet. I så fall är K. ett objekt av kategorin eller klassen Anställd. För att beskriva K. kan man lika bra beskriva alla an- 25 Anställd - förnamn - efternamn - födelsedatum - anställningsdatum - arbetstid + lön() + presentera() + morgonsyssla()