C++ProvKapitel - Polyformia AB

Download Report

Transcript C++ProvKapitel - Polyformia AB

Programmering
för nybörjare
med
C++
Nybörjarserie i programmering, Bd. I
Täcker Programmering A, B och C
av
Taifun Alishenas
Förlag
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 [email protected]
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
Taifun Alishenas
Förlag
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 44), hur man använder Visual C++ i Microsofts
.NET-miljö (sid 39) samt hur man bygger en egen programutvecklingsmiljö för C++ med gratis programmet TextPad (sid 47).
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.
4H
5H
6H
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 [email protected].
Stockholm i december 2007
Taifun Alishenas
Teknologie Doktor
4
Innehållsförteckning
Programmering A
Ämne
Sida
Kapitel 1 Introduktion till programmering
1.1
Vad är programmering?
1.2
Vad är en algoritm?
1.3
Olika sätt att beskriva en algoritm
1.4
Pseudokod och flödesplan
1.5
Vad är objektorienterad programmering?
‐ Objekt, klass och metod
‐ Objektorienteringens termer
1.6
Programmering: En kort historik
Övningar till kapitel 1
11
12
14
17
18
23
23
25
29
33
Kapitel 2 C++ miljöer
2.1
Dev-C++: En grafisk utvecklingsmiljö
2.2
Microsofts .NET-miljö Visual Studio
2.3
Borland: En textbaserad kompilator
2.4
En egen utvecklingsmiljö med TextPad
2.5
Att köra C++ i ett kommandofönster
35
36
39
44
47
52
Kapitel 3 Att komma igång med C++
3.1
Reserverade ord
3.2
Hur får man in programmet i datorn?
3.3
Vårt första C++ program
3.4
Utskrift till skärmen
3.5
Konkatenering
Övningar till kapitel 3
55
56
58
61
65
67
68
69
Kapitel 4 Grundbegrepp i programmering
4.1
God programmeringsstil
4.2
Datatyper och variabler
4.3
Definition och initiering av variabler
‐ Oinitierade och väl definierade variabler
‐ Definition och initiering i samma sats
‐ Objektorienterad initiering
‐ Deklaration vs. definition
4.4
Överskrivning eller kan x = x + 1 vara sant?
4.5
Inläsning av värden
4.6
Aritmetiska operatorer och uttryck
‐ Inmatning – Bearbetning – Utmatning
4.7
Ökningsoperatorn ++
4.8
Sammansatt tilldelning
Övningar till kapitel 4
71
72
74
78
81
82
83
84
87
89
91
92
93
95
97
5
Program
01First
02cout
03Concat
04Figur
05Datatyp
06Variabel
07Oinitierad
08DefInit
09ObjInit
10Dekl/10Def
11Overwrite
12cin
13TimSek
14PlusPlus
15SamTilld
Ämne
Sida
Kapitel 5 Enkla datatyper
5.1
Datatypen char
5.2
Explicit typkonvertering
Sammanfattning av kapitel 4 och 5
Övningar till kapitel 5
99
100
102
103
104
107
110
112
113
115
115
117
118
119
121
122
123
Kapitel 6 Kontrollstrukturer
6.1
Algoritmers byggstenar
6.2
Enkel selektion: if-satsen
‐ Block
6.3
Tvåvägsval: if-else-satsen
6.4
Flervägsval
‐ Luriga else
‐ Nästlad if-else
‐ switch-satsen
‐ switch med tomma case-satser
‐ Kombination av switch och if-else
6.5
Spagetti-programmering
6.6
Efter-testad repetition: do-satsen
6.7
För-testad repetition: while-satsen
‐ Evighetsslinga
6.8
Bestämd repetition: for-satsen
‐ Jämförelse mellan for och while
‐ ASCII-tabellen med for
6.9
Nästlade for-satser
‐ Hantering av slumptal
‐ Multiplikationstabellen
Övningar till kapitel 6 (Projekt Labyrint I)
125
126
127
131
132
135
135
137
138
141
143
144
146
149
150
151
153
154
157
158
161
163
5.3
5.4
5.5
5.6
ASCII-tabellen
Escapesekvenser
De enkla datatypernas gränser
‐ Heltalstypernas gränser
‐ Decimaltalstypernas noggrannhet
Automatisk typkonvertering
‐ vid tilldelning: Tilldelningsregeln
‐ vid aritmetiska operationer: int-regeln
‐ Befordringsregeln
6
Program
16Kod
17char2int
18int2char
19Ascii
20Escape
21Enkla
22Limits
23Digits
24TilldRegel
25Overflow
26intRegel
27BefHeltal
28BefFlyttal
29if
30ifBlock
31ifelse
32LurigaElse
33NestedIfElse
34switch
35switchOlik
36GissaSwitch
37Spagetti
38GissaDo
39while
40forWhile
41AsciiFor
42Stars
43NestedFor
44MultNestFor
Programmering B
Ämne
Sida
Kapitel 7 Logik för blivande programmerare
7.1
Sammansatta villkor
‐ Logiska operatorer
‐ De logiska operatorerna OCH och ELLER
7.2
Datatypen bool
7.3
NEGATION som logisk operator
‐ Logiska uttryck
‐ Test av lösenord med NEGATION
‐ Datatypen string
7.4
Logiska lagar
‐ Test av lösenord med De Morgans lag
Övningar till kapitel 7 (Projekt Labyrint II)
Kapitel 8 Funktioner
8.1
Vad är en funktion?
8.2
Definition och anrop av funktioner
8.3
Deklaration av funktioner
8.4
Externlagrad funktion
165
166
167
168
173
175
176
177
177
178
180
181
182
Övningar till kapitel 8
183
184
187
193
196
197
199
200
201
202
203
207
209
210
213
215
216
218
220
221
222
223
Kapitel 9 Array - en sammansatt datatyp
9.1
Vad är en array?
9.2
Definition och initiering av en array
- Initieringslista
9.3
Stränghantering med array
‐ Nolltecknet
225
226
228
230
233
233
8.5
Funktioner utan returvärde
8.6
8.8
8.9
8.10
Lokala och globala variabler
‐ Blockstruktur
Överskuggning av variabler
‐ Räckviddsoperatorn
Värdeanrop:
Call by value
Referenser
Referensanrop: Call by reference
8.11
In- och utparametrar
8.12
Överlagring av funktioner
8.7
7
Program
45Logik
46Kors
47NegativtKors
48SannTab
49GissaLog
50PasswordNeg
51DeMorgan
52PasswdMorgan
53PasswdMorgan
54Funktion
55Slumptal
56ExternFunk
56netto
57compare
57GissaVoid
slumpTal
58Global
59Scope
60CallByVal
61Referens
62platsbyte
62CallByRef
63vaxel
63VaxelTest
64potens
64Overload
65ArrayDef
66ArrayInit
67ArrayChar
68Nolltecknet
Ämne
9.4
9.5
Array som parameter i funktioner
- Referensanrop med array
Sökning och sortering
- Slumptal i en array
- Minimax-problemet
- Namngivna konstanter och skalbarhet
- Bubbelsortering
9.6
Kryptering av text
9.7
Tvådimensionell array
Övningar till kapitel 9 (Projekt Labyrint III, Master Mind)
Sida
Program
240
242
244
245
246
247
249
251
253
255
256
258
262
69RefArray
slumpArray
70SearchTest
70search
71minimax
71MinimaxTest
72bubbel
72BubbelTest
73KryptTextTest
73kryptText
74DoubleArray
Programmering C
Kapitel 10 Filhantering
10.1 Att skriva till och läsa från filer
10.2 Slumplösenord
75WriteReadFile
76RandPasswTest
76randPassw
77KryptFil
77kryptText2
77readShowFile
77writeFile
78setTable
78writeTable
78readShowTable
78TableFile
78updateTable
Övningar till kapitel 10
265
266
270
271
273
275
276
276
277
279
280
281
281
284
Kapitel 11 Pekare
11.1 Vad är en pekare?
11.2 Definition och initiering av en pekare
11.3 Adress- och värdeoperatorn
11.4 Pekare och referens
11.5 Operatorn new
11.6 Pekare och array
‐ Pekararitmetik
11.7 Stränghantering med pekare
11.8 Referensanrop med pekare
11.9 Dynamisk minnesallokering
‐ Datorns interna minneshantering
285
286
288
291
297
299
303
305
307
311
315
315
79Pekare
80Varde
81PekRef
82new
83PekArray
84PekAritm
85Initialer
86RefPek
10.3
Kryptering av filer
10.4
2D array som parameter i funktioner
‐ Tabellhantering i filer
8
Ämne
Sida
Program
‐ Dynamisk array
‐ Nollpekaren
11.10 Dynamisk filkryptering
Övningar till kapitel 11
317
319
321
324
87Dynamic
Kapitel 12 Objektorienterad programmering
12.1 Vägen till objektorienterad programmering
Polymorfism
‐ Överskuggning av metoder
‐ Åtkomstmodifieraren protected
Övningar till kapitel 12 (Projekt Automat)
325
326
327
328
331
332
334
335
337
339
340
342
343
347
350
351
352
356
357
358
360
362
363
365
366
367
367
369
372
374
375
376
378
379
382
Programförteckning
Sakregister
384
389
12.2
12.3
12.4
12.5
‐ Vår första klass
‐ Test av klass
‐ Objekt och klass
Klass som datatyp
‐ Deklaration av klass
‐ Definition av objekt
‐ Åtkomst till objektets medlemmar
‐ Punktnotation
Metoder
‐ Objekt som parameter och returvärde
Objektorienterad modellering
‐ Implementation av modellen
‐ Array av objekt
‐ Referens till objekt
Inkapsling och klassens konstruktor
‐ Åtkomstmodifieraren private
‐ Klassens konstruktor
‐ Default-konstruktorn
‐ Flera konstruktorer
12.6
Åtkomstmetoder
12.7
Komposition
‐ Komposition av klasser
‐ Komposition av objekt
Arv
‐ Arvrelationen
12.8
12.9
9
88DynKryptFil
89Allt_i_main
90Procedural
91Cirkel
91ObjOrienterad
92Anstalld
92EgenDatatyp
93Restid
93RestidTest
94Tid
94TimAnstalld
94Arbetstid
95Circle
95Inkapsling
96Circles
96Constructors
97Emp
97Access
98Date
98Employ
98Composition
99Person
99Employee
99Inheritance
100Konto
100MinimalKonto
100SkapaKonto
10
Kapitel 1
Introduktion
till programmering
1.1
1.2
1.3
1.4
1.5
Vad är programmering?
Vad är en algoritm?
Olika sätt att beskriva en algoritm
Pseudokod och flödesplan
Vad är objektorienterad programmering?
‐ Objekt, klass och metoder
‐ Objektorienterad modellering
1.6
Programmering: En historik
Övningar till kapitel 1
11
12
14
17
18
23
23
25
23
33
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
(dator)
Maträtt (utdata)
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.
II.
III.
IV.
V.
Gå upp kl. 6
Duscha TILLS kroppen känns fräsch
Torka och ta på kläderna
Ät frukost och lyssna på radio
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.
Start/Slut
Instruktion 1
Ett villkor ritas som romb.
Villkoret skrivs in i romben och kan även formuleras som fråga.
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
Loop*
Duscha
Kroppen
fräsch?
nej
ja
Torka och ta på sig kläderna
Äta frukost & lyssna på radio
ja
Gå ut
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 algoritmaspekAnställd
ten. I det här fallet är objektet K. som utför algoritmens instruktioner för att ta sig till jobbet. Den
- förnamn
primära frågan är nu: Vem är K. eller hur kan K.
- efternamn
- födelsedatum
beskrivas? Hur han gör för att ta sig till jobbet
- anställningsdatum
kommer att ingå som en del i denna beskrivning.
- arbetstid
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 an25
+ lön()
+ presentera()
+ morgonsyssla()
ställda. Därför definieras en klass som beskriver alla anställda och K. görs till ett objekt,
ett exemplar av denna klass. På så sätt kan koden återanvändas även för andra anställda.
Återanvändning av kod gör utvecklingsarbetet av programvara effektivare och är en av
den objektorienterade synens fördelar. I klassen Anställd ingår all typ av information som
är relevant för en anställd, det vi kallade för attribut, t.ex. för- och efternamn, födelse- och
anställningsdatum, arbetstid osv. Dessutom tar vi upp allt som en anställd kan göra, det vi
kallade för metoder, t.ex. att få lön, att presentera sig eller, varför inte, att ta sig till jobbet.
På så sätt blir algoritmen Morgonsyssla i den objektorienterade programmeringens terminologi en metod i klassen Anställd. Ett verktyg som har utvecklats speciellt för objektorienterade modelleringar är UML (Unified Modeling Language) som nämndes tidigare
(sid 17). Enligt det här modelleringsspråket skulle klassen Anställd beskrivas med ett
diagram (ovan) där tecknet – står för attribut och + för metoder.
Datamedlemmar
När man kommer till implementeringen av modellen, dvs skriver C++ kod, brukar man
använda termen datamedlem för attribut. En klass består då av datamedlemmar och metoder. Klassen Anställd t.ex. har fem datamedlemmar och tre metoder.
Arv
Person
- förnamn
- efternamn
- födelsedatum
+ presentera()
+ morgonsyssla()
I den reala världen som vi vill efterlikna, finns inga
isolerade objekt. Alla objekt är mer eller mindre relaterade till andra objekt. En klok modellering måste
dra nytta av de befintliga relationer mellan objekt för
att effektivisera och optimera utvecklingsarbetet. En
sådan relation är arvrelationen.
Man kan alltid etablera en arvrelation mellan två begrepp om de står i en en ”är”-relation till varandra. I
exemplet ovan kan vi konstatera ett en anställd är en
person. Därför kan klassen Anställd ärva klassen
Person, närmare bestämt ärver klassen Anställd
klassen Person:s alla datamedlemmar och metoder.
Klassen Person kallas bas- eller superklass. KlasAnställd
sen Anställd kallas härledd eller subklass. Sub- anställningsdatum
klassen ärver superklassens alla datamedlemmar och
- arbetstid
metoder, vilket i praktiken innebär att klassen Anställd tar över all kod som redan finns i klassen
+ lön()
+ morgonsyssla()
Person och lägger till ny kod som närmare specificerar en anställd. På så sätt slipper man skriva om
kod som redan finns. T.ex. har en person ett för- och efternamn samt ett födelsedatum.
Vid modellering av en anställd ärvs dessa attribut, och man lägger till de nya attributen
anställningsdatum och arbetstid som är speciella för anställden. UML-diagrammet ovan
(till vänster) visar modellen där arvrelationen ritats med en pil riktad mot superklassen.
Följer man pilens riktning underifrån kan man avläsa att det är klassen Anställd som
ärver klassen Person.
26
Observera att klassen Anställd inte har två utan fem attribut därför att den via arvrelationen även har Person-klassens tre attribut. Samma gäller för metoderna: Anställdklassen ärver metoden presentera() från klassen Person. Modellen ovan går utifrån
att personer presenterar sig på samma sätt som anställda. Sedan har anställda en löneberäkningsmetod som icke-anställda personer saknar. Men varför står metoden morgonsyssla() i båda klasser? Närmare bestämt: Varför förekommer den i Anställd-klassen fast den ärver den från superklassen? Svaret ges av ett annat koncept inom objektorienterad programmering:
Polymorfism
Modellen ovan går utifrån att icke-anställda personer har en annan form av morgonsyssla än anställda. De kanske inte tar sig till jobbet, i alla fall inte alla, utan har en annan morgonsyssla. Så vi har här att göra med två olika morgonsysslor tillhörande två
olika klasser, men med samma namn. För objekt av typ Person kommer den ena och
för objekt av typ Anställd kommer den andra att gälla. Men varför har de samma
namn? Vore det inte bättre, för att undvika namnkonflikt, att ge dem olika namn, när de
ändå är olika metoder? Faktiskt inte!
Anledningen till att de har samma namn är följande: För det första blir det ingen namnkonflikt därför att de tillhör olika typer av objekt. De är inte fristående utan inkapslade i
var sitt objekt som skiljer åt dem. För det andra ska vi inte i onödan göra utvecklingsarbetet komplicerat genom att hitta på nya namn på metoder som skiljer sig från varandra endast i detaljer. Ingen människa skulle kunna komma ihåg så många namn. För det
tredje vill vi efterlikna verkligheten där det bara kryllar av beteckningar som är identiska, men har olika innebörd i olika sammanhang. Inte heller det vanliga språket har olika
namn på dem. Ta följande exempel: Att bromsa en lastbil görs på ett annat sätt än att
bromsa en båt. Det finns ingen anledning att hitta på ett annat namn för funktionaliteten
"att bromsa" hos olika typer av fordon. Tvärtom, det vore förvirrande att använda olika
namn. Man vill ju helst slippa att tänka på de tekniska skillnaderna mellan olika typer
av fordon när man pratar om bromsning. En och samma funktionalitet är realiserad på
olika sätt. Med andra ord, man gör "samma sak", fast på annorlunda sätt. Objektorienterad programmering tar över detta koncept genom att välja ett och samma namn för olika
metoder. När metoderna dessutom finns i klasser som ärver varandra kallas konceptet
för polymorfism. ”Poly” betyder många och ”morf” är form eller gestalt på latin och antik grekiska. Polymorfism handlar om en sak som har många olika gestalter, t.ex. ett ord
som har många olika betydelser.
Polymorfism modifierar helt eller delvis funktionaliteten hos metoder
med samma namn som förekommer i en arvhierarki.
En metod beskriver alltid någon funktionalitet. Polymorfism förändrar denna funktionalitet genom att definiera en metod i superklassen och definiera om innehållet, men behålla namnet i subklassen.
27
Objektorienterad programmering har kommit till för att förverkliga programmeringens
gamla önskedrömmar om modularisering, återanvändning av kod och strukturering av
program – allt för att kunna underhålla stora program, förnya och vidareutveckla dem
så att de fungerar över längre tid och snabbt kan anpassas till nyuppkomna situationer.
Objektorienterad programmering bygger på tre hörnstenar:
•
•
•
Inkapsling
Arv
Polymorfism
De två sista har vi försökt att introducera här utan att behöva skriva en enda rad kod.
För den första behöver vi lite mer detaljerade kunskaper om programmering.
Några konventioner
När vi ritade UML-diagrammen ovan och skrev text i dem tillämpade vi några konventioner som man i regel brukar använda inom programmering. Vi kommer att följa dem
även i fortsättningen:
1. Klasser inleds med versaler
För att bättre kunna känna igen klasser i objektorienterad kod, inleds de med versaler. Så därför skriver vi klasserna Anställd och Person så här. Följer man konsekvent alla konventioner (även punkt 2 nedan) kan man lätt avgöra att ett ord i koden
som har en stor begynnelsebokstav, är en klass, antingen ur C++:s klassbibliotek eller en egendefinierad sådan.
2. Attribut, metoder och objekt inleds med gemener
Till skillnad från klasser inleds alla attribut, metoder och objekt med gemener, t.ex.
förnamn, efternamn, arbetstid, … som är attribut eller lön(), morgonsyssla(), … som är metoder. Även den här konventionen höjer kodens läslighet när
den följs i kombination med punkt 1.
3. Metoder skrivs med parentes
Till skillnad från ett attribut som kan ha ett värde, beskriver en metod en funktionalitet som kan anropas från en annan metod vilket medför att man vid anropet kan
skicka vissa parametrar till den anropade metoden. Dessa parametrar skrivs inom
en parentes direkt efter metodens namn. På så sätt är parentesen kännetecknet för
en metod. Även om en viss metod inte har någon parameter alls som i våra exempel
med lön(), morgonsyssla(), … brukar man ändå skriva den tomma parentesen
med. Detta är en regel när man skriver kod, men har blivit en konvention som man
även följer utanför programkod.
28
1.6 Programmering: En kort historik
Redan på 1800-talet programmerade man vävstolarna med ett slags jättelika hålkort vilket
kan betecknas som en form av manuell programmering. Speldosor av olika slag vars melodier är förprogrammerade och stansade i cylinderformiga metalltrummor som rullar
över en spik (1800-talets MP3-spelare!), är ett annat exempel på manuell programmering.
Även när de första datorerna konstruerades på 1930/40-talet, skedde all programmering
manuellt. Man matade de stora maskinerna med både information (data) och instruktion
(program) för att åstadkomma en liten beräkning. Dessa jätteapparater med en bråkdel av
datorkraften hos en modern PC (en av dem: 35 ton och 16 meter lång) kunde lagra data.
Men att även kunna lagra instruktioner, var ett problem.
Först 1944 lyckades John von Neumann att konstruera en dator som kunde lagra både data och instruktioner. Informationen matades in via hålkort, och sedan kunde man bearbeta
den och t.o.m. ändra instruktionerna i datorn.
Dator
Indata
Utdata
Primärminnet
Program
Från maskinkod till Assembler
Det är till denna tidpunkt (1944) man kan datera den moderna programmeringens födelse.
Även idag fungerar programkörning i princip på samma sätt: programmet laddas från
hårddisken, där det lagrats i en fil, till datorns primärminne. Indata matas in från tangentbordet eller hämtas från en annan fil. I primärminnet bearbetas indata enligt programmets
instruktioner, dvs utdata produceras och matas ut. Enda skillnaden från idag: då bestod instruktionerna av långa talkedjor som omvandlades till ettor och nollor, dvs man programmerade i maskinkod, ett språk som datorns processor förstår. Man kom så småningom på
idén att använda sig av kortkommandon på engelska som motsvarade instruktionerna i
talform. Ett litet program tolkade sedan kortkommandona till maskinkod dvs ettor och
nollor. Programmet kallades assembler eller assemblator. De (halv)engelska kortkommandona var de första nyckelorden av programmeringsspråket Assembler.
Programmeringens historia skulle kunna fylla hela boken. Vi däremot måste nöja oss med
ett urval. Därför tar vi endast upp några få programspråk. Genomgången nedan gör alltså
inte alls något anspråk på fullständighet. Samtidigt ska den förklara varför det finns så
många (flera hundra) olika programspråk.
50-talet
Assembler betecknas som lågnivåspråk eftersom det är nära datorns språk
utan att vara maskinkod. Fördelen med Assembler är att det är snabbt. Än idag
finns det ingen kod skriven av människan som kan köras på datorn snabbare.
Nackdelen med Assembler är att det inte finns ett språk som heter så, utan var29
je processor har sitt eget assemblerspråk. Dvs program skrivet för en datortyp
kan inte köras på en annan. På 40-talet var datorerna tekniska underverk, byggda för hand. Varje dator hade sin egen programmerare, oftast tillverkaren själv
som var specialiserad på just sin maskins assemblerspråk. I längden var detta
ohållbart. Lösningen var att komma bort från maskinberoende språk.
1957
FORTRAN = FORmula TRANslator är historiens första högnivåspråk i den be-
märkelsen att det ligger nära människans språk. Avståndet till maskinkod är
större än hos Assembler. Därför måste en källkod i Fortran först översättas till
maskinkod. Denna översättning kallas kompilering och är mer invecklad än assemblering. Den nya maskinkod som direkt kan köras, är mycket större än
källkoden och lagras separat på hårddisken. Fortran är till skillnad från Assembler ett kompilerande språk. Dessutom är det som namnet antyder, i första
hand inriktat på beräkning av matematiska formler. Än idag används fortranprogram av ingenjörer och vetenskapsmän som behöver snabba beräkningar.
Men det finns även administrativa tillämpningar av Fortran. Språket är från
början utvecklat och marknadsförs av företaget IBM.
1959
COBOL = COmmon Business Oriented Language är, som namnet säger, spe-
cialiserat på administrativa och ekonomiska tillämpningar. Det kräver hantering av stora datamängder vilket Cobol är bra på. Många stora banker och försäkringsbolag har kvar sina program som en gång var skrivna i Cobol. Även
om det numera finns modernare språk, håller man ofta fast vid det gamla pga
de stora kostnader som ett byte skulle innebära. Även Cobol är ett högnivåspråk och därmed kompilerande. Cobol är utvecklat av USA:s försvarsdepartement i samarbete med den amerikanska datorindustrin.
1960
ALGOL = ALGOrithmic Language är det första språk som utvecklades i Europa. Det hade akademisk bakgrund: Initiativet låg hos det tyska GAMM (Gesellschaft für Angewandte Mathematik und Mechanik). Man var ute efter ett verktyg för att utnyttja datorkraften för teknisk-vetenskapliga beräkningar på ett
mer strukturerat sätt än Fortran. Beräkningarna skulle baseras på numeriska algoritmer snarare än matematiska formler. Algol som var ett kompilerande högnivåspråk, berikade programmeringen med många nya idéer och introducerade
bl.a. kontrollstrukturerna som används i algoritmer. Dessa har tagits över och
vidareutvecklats i de moderna programspråken. Algol själv används inte så
mycket idag, inte minst pga brist på marknadsföring.
1963
BASIC = Beginners All-purpose Symbolic Instruction Code är ett av de få ge-
nerella högnivåspråk som inte är kompilerande utan interpreterande. Dvs källkoden tolkas rad för rad av datorns processor, utförs direkt och glöms bort
sedan. Det uppstår ingen ny kod som lagras på hårddisken. Interpretering av
källkod är alltid långsammare än exekveringen av redan kompilerad maskinkod. Däremot är interpretering snabbare än kompilering av källkod. I Basic
finns inget kompileringssteg. Basic är, som namnet berättar, inriktat på att lära
ut programmering för nybörjare. Därför har man hållit språket så enkelt som
möjligt, så enkelt att man struntat i kontrollstrukturer som redan fanns i Algol
30
och därmed lagt grunden för hoppsatser (se sid 144 om Spagettiprogrammering). Basic utvecklades ursprungligen av Dartmouth College i USA, men har
sedan tagits över av Microsoft och integrerats som QuickBasic i DOS och
Windows. På 90-talet har Microsoft lanserat vidareutvecklingen Visual Basic
som blivit ett modernt och populärt utvecklingsverktyg. Den nyaste versionen
heter Visual Basic.NET och är objektorienterad. I Visual Basic kan man även
generera en exekverbar kod i efterhand genom att kompilera källkoden.
1971
Pascal är ingen förkortning för något utan har uppkallats efter Blaise Pascal
som konstruerade räknemaskinen 1652. Pascal utvecklades av Niklaus Wirth
på ETH (Eidgenössische Technische Hochschule) i Zürich. Tanken var att skapa ett kompilerande språk för att lära ut programmering för nybörjare genom
att kombinera Basics enkelhet med Algols logiska strukturer och dess algoritmiska upplägg. På 80-talet utvecklade mjukvaruföretaget Borland Turbo-Pascal som blev en stor succé pga kompilatorns snabbhet och den integrerade
programutvecklingsmiljön (IDE) som möjliggjorde kompilering, felsökning,
editering och online hjälp i en och samma miljö. Idag marknadsför Borland
Pascals objektorienterade vidareutveckling Delphi.
1972
C har utvecklats av Dennis Ritchie på Bell Laboratories med syftet att skapa
ett språk för programmering av operativsystemet Unix. I den bemärkelsen är C
en biprodukt av Unix. Därför finns många logiska paralleller mellan C/C++
och Unix (fotnot sid 61). Idag är inte bara Unix utan alla stora operativsystem
inkl. Windows skrivna i C/C++. Styrkan i C består av en kombination mellan
enkelhet – hela språket är definierat av endast 32 nyckelord – strukturell elegans och möjligheten att lätt kunna kommunicera med datorns hårdvara. C har
bland de moderna språken den bästa förmågan att hantera och kontrollera
hårdvaran, vilket favoriserar C som programspråk för operativsystem. I det avseendet liknar C mycket Assembler utan att dela lågnivåspråkets nackdelar.
Man har därför också kallat C för ett kompilerande mellannivåspråk. Den stora frihet som C erbjuder för hantering av bl.a. datorns primärminne med hjälp
av pekare, kod som ger åtkomst till den fysiska adressen till data och på gott
och ont tillåter manipulationer av minnesadresser genom pekararitmetik.
80-talet
C++ är en direkt utvidgning och vidareutveckling av C. Det var dansken Bjarne Stroustrup som la grunden till denna utveckling. Under 70-talet hade man
nämligen konstaterat att procedural eller strukturerad programmering (Algol,
Pascal, C) inte längre tillgodosåg alla behov som stora komplexa program
ställde med avseende på underhåll, förnyelse och ändringsbarhet. Ingen kunde
sätta sig in i, ändra och vidareutveckla ett stort program om programmeraren
hade lämnat företaget. Det innebar ett enormt slöseri av resurser. Dessutom
utvecklades hårdvaruteknologin så snabbt att program som kunde köras på de
allt mer avancerade datorerna blev allt större och mer komplexa, speciellt på
det grafiska området. Mjukvaruteknologin utvecklades inte alls i samma takt.
För att lösa alla dessa problem, uppkom en ny programmeringsfilosofi som
kallas objektorienterad programmering som en vidareutveckling av den traditionella procedurala eller strukturerade programmeringen. I definitionen Pro31
gram = data + algoritm försköts huvudvikten från algoritm till data, där data
inte längre betraktades endast som nödvändig information – en slags bilaga till
algoritmen – utan som objekt. Med det menas ett exemplar av den klass som
definierar alla egenskaper av liknande objekt, en återanvändbar kodkomponent
som modellerar verkligheten (behandlas i bokens sista kapitel).
Bjarne Stroustrup bibehöll hela C och la till de nya objektorienterade elementen, bl.a. klassbegreppet, som redan fanns t.ex. i Simula, ett norskt programmeringsspråk från 1967 som var en direkt utbyggnad av Algol. Simulas klasser
hade ”glömts bort”. Den beskrivna problematiken på 70-talet gjorde att man
kom ihåg dem. Förhållandet mellan C och C++ illustrerar bäst tilläggskaraktären av den ”nya” filosofin.
C++
C
Med andra ord, C är delmängd av C++. Medan C har 32 nyckelord, finns i
C++ enligt den internationella standarden 62 nyckelord, inklusive alla C-nyckelord. Därför kan en C++ kompilator kompilera all kod skriven i C, men inte tvärtom. Så, den som lär sig C++, lär sig automatiskt C. Denna bok använder C++ direkt utan att explicit gå in på C. I själva verket behandlar bokens
procedurala del C-språket som en del av C++.
90-talet
Java är en modernisering av C++ som motiverades av en annan utveckling
inom IT. Man kan kalla det för den grafiska eller Webbrevolutionen. C++ är
ett kraftfullt och populärt utvecklingsverktyg, men dess styrka ligger fortfarande på textbaserade tillämpningar. Inte att C++ vore olämpligt för grafiska
tillämpningar, bara att det är lite jobbigt att skriva C++ kod för att åstadkomma grafik. En anledning är att, när C++ skapades, hade grafiska tillämpningar
bara en begränsad spridning. Med utvecklingen av webben och dess grafiska
miljö, med spridningen av Windows och grafiska användargränssnitt blev grafiken dominant. Idag är ett program utan grafiskt användargränssnitt inte särskilt populärt. Java som urspungligen utvecklades av Sun Microsystems som
ett projekt för att skapa ett språk för programmering av hushållsmaskiner, är
från början inriktat på grafik. Hushållsprojektet visade sig vara en bubbla som
sprack som mycket annat inom IT. Webben, som revolutionerade IT, blev räddaren i nöden för Java. Men dagens Java är inte bara grafik och webb. Sun satsade på att utveckla Java till ett modernt objektorienterat språk och lyckades
med det. Javas plattformsoberoende egenskap var avgörande för denna framgång. Språket spreds med en snabbhet som inget annat språk hittills uppnått.
Idag är Java ett universellt programmeringsspråk för alla möjliga tillämpningar, även för webbapplikationer t.ex. Java Server Pages (JSP).
32
Övningar till kapitel 1
1.1 Rita flödesplanen till följande algoritm som är formulerad med pseudokod:
Start hårtvätt
Blöt håret
SÅ LÄNGE håret känns smutsigt
massera in shampo
skölj
OM solen skiner
låt håret självtorka
ANNARS
använd hårtorken
Slut hårtvätt
Vilka delar är instruktioner, vilka är villkor och vilka är kontrollstrukturer.
Dela in instruktionerna i huvud- och underinstruktioner.
1.2
Följande algoritm är formulerad med vanligt språk:
På vardagar går Kalle upp. Han tvättar sig, om mamman tittar på.
På söndagar sover Kalle vidare tills mamman ropar
honom till frukost, i så fall gör han som på vardagar.
Behandla lördagen som en vardag.
Rita först flödesplanen och översätt den sedan till pseudokod.
Finns det i algoritmen möjligheten till en evighetsloop? När skulle den rent
teoretiskt kunna inträffa?
1.3 Rita flödesplanen till följande pseudokod som formuleras med nästlade tvåvägsval:
Start vinterklädsel_1
Läs av temperaturen
OM temperatur < 0
ta sjal, mössa och handskar
ANNARS
OM temperatur < 5
ta sjal och mössa
ANNARS
OM temperatur < 10
ta sjal
ANNARS
slipper du sjal, mössa och handskar
Slut vinterklädsel_1
1.4 Samma algoritm som i övning 1.3 kan formuleras med flervägsval:
33
Start vinterklädsel_2
Läs av temperaturen
VÄLJ fall ur
temperatur < 0: ta sjal, mössa och handskar
temperatur < 5: ta sjal och mössa
temperatur < 10: ta sjal
Annars: slipper du sjal, mössa och handskar
Slut vinterklädsel_2
Rita flödesplanen till pseudokoden ovan och undersök den logiska likheten
mellan flödesplanerna i 1.3 och 1.4.
1.5 Rita flödesplanen till följande pseudokod:
Sätt på radion
Välj en kanal och lyssna
SÅ LÄNGE du inte har hittat ett bra program
byt kanal
lyssna
Fortsätt att lyssna på det valda programmet
Stäng av radion
1.6
Formulera en algoritm med vanligt språk som beskriver din morgonsyssla
på vardagar. Rita först flödesplanen och skriv sedan pseudokoden.
Modifiera algoritmen så att den beskriver din morgonsyssla på söndagar.
1.7
Formulera en algoritm med vanligt språk som beskriver vägen till nöjesfältet
i dina hemtrakter. Försök att bygga in minst en selektion och en repetition i
algoritmen. Tips: vädret t.ex. kan ge upphov till selektion. Rondeller, väntetider mm. kan ge upphov till repetitioner. Rita först flödesplanen och översätt den sedan till pseudokod.
1.8
Rita flödesplanen till följande pseudokod:
Start heltalstest
Ta ett positivt heltal
REPETERA
OM heltalet är udda
multiplicera heltalet med 3 och addera 1
ANNARS
dividera heltalet med 2
TILLS heltalet = 1
Slut heltalstest
Testa algoritmen på små heltal med hjälp av en kalkylator.
34