Programsystemkonstruktion med C++: ¨Ovning 1
Programsystemkonstruktion med C++: ¨ Ovning 1
Karl Palmskog palmskog@kth.se
september 2010
Klassens uppbyggnad
en C++-klass best˚ ar av en deklaration och en definition deklaration vanligtvis i .h (.hh) och definition i .cpp (.cc) private ¨ ar f¨ orvalt f¨ or funktioner och variabler i klasser globala funktioner och variabler ¨ ar OK
main ¨ ar en global funktion
macro (inleds med #) k¨ ors av preprocessorn innan kompilering
Programsystemkonstruktion med C++: ¨Ovning 1 Programuppbyggnad
Exempel p˚ a deklaration: inventory item.h
#i f n d e f INVENTORY ITEM H
#d e f i n e INVENTORY ITEM H
#i n c l u d e <c s t d d e f >
c l a s s I n v e n t o r y I t e m {
p r i v a t e : d o u b l e c o s t ;
s i z e t u n i t s ; p u b l i c :
s t a t i c c o n s t d o u b l e DEF COST = 1 0 ; s t a t i c c o n s t s i z e t DEF UNITS = 1 0 0 ;
I n v e n t o r y I t e m ( ) : c o s t ( DEF COST ) , u n i t s ( DEF UNITS ) {}
I n v e n t o r y I t e m ( d o u b l e c , s i z e t u ) ;
˜ I n v e n t o r y I t e m ( ) {}
d o u b l e v a l u e ( ) c o n s t ; v o i d r e m o v e U n i t s ( s i z e t u ) ; } ;
#e n d i f
Exempel p˚ a definition: inventory item.cpp
#i n c l u d e ” i n v e n t o r y i t e m . h ”
I n v e n t o r y I t e m : : I n v e n t o r y I t e m ( d o u b l e c , s i z e t u ) { c o s t = c < 0 ? 0 : c ;
u n i t s = u ; }
d o u b l e I n v e n t o r y I t e m : : v a l u e ( ) c o n s t { r e t u r n c o s t ∗ u n i t s ;
}
v o i d I n v e n t o r y I t e m : : r e m o v e U n i t s ( s i z e t u ) { i f ( u > u n i t s ) {
u n i t s = 0 ; } e l s e {
u n i t s −= u ; }
}
Programsystemkonstruktion med C++: ¨Ovning 1 Programuppbyggnad
Exempel p˚ a anv¨ andning av klassdeklaration: main.cpp
#i n c l u d e ” i n v e n t o r y i t e m . h ”
#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ; i n t main ( )
{
I n v e n t o r y I t e m d e f a u l t I t e m ;
c o u t << d e f a u l t I t e m . v a l u e ( ) << e n d l ; I n v e n t o r y I t e m c u s t o m I t e m ( 2 0 , 2 0 0 ) ; c o u t << c u s t o m I t e m . v a l u e ( ) << e n d l ; c u s t o m I t e m . r e m o v e U n i t s ( 5 0 ) ;
c o u t << c u s t o m I t e m . v a l u e ( ) << e n d l ; c u s t o m I t e m . r e m o v e U n i t s ( 2 5 0 ) ;
c o u t << c u s t o m I t e m . v a l u e ( ) << e n d l ; r e t u r n 0 ;
}
Exempel p˚ a kompilering och k¨ orning av program
Kompilering med g++ direkt till program och k¨ orning:
$ g++ −o i i main . cpp i n v e n t o r y i t e m . cpp
$ . / i i 1000 4000 3000 0
Ekvivalent med objektfiler kompilerade var f¨ or sig:
$ g++ −c i n v e n t o r y i t e m . cpp
$ g++ −c main . cpp
$ g++ −o i i main . o i n v e n t o r y i t e m . o
Med varningar, avlusningssymboler och optimering:
$ g++ −o i i d e b u g −W a l l −g −O1 main . cpp i n v e n t o r y i t e m . cpp
Programsystemkonstruktion med C++: ¨Ovning 1 Kompilering och k¨orning av program
Programmets v¨ ag till exekvering
Objektkod
Kompilator (.o) L¨ankare
Startkod Bibliotekskod
(.so, .a, .dll, ...) K¨allkod
(.c, .cpp, .h, ...)
Exekverbar kod (.exe, ...)
Beroendehantering
om vi ¨ andrar main.cpp r¨ acker det att kompilera om den om vi ¨ andrar i inventory item.cpp/h m˚ aste vi eventuellt kompilera om b˚ ade inventory item.cpp och main.cpp jobbigt h˚ alla reda p˚ a beroenden
l˚ angsamt att alltid kompilera om allt
“intressanta” fel om allt som beh¨ over kompileras inte kompileras om
en l¨ osning: anv¨ and verktyget make
Programsystemkonstruktion med C++: ¨Ovning 1 Kompilering och k¨orning av program
En enkel makefil
i i : main . o i n v e n t o r y i t e m . o
g++ −o i i main . o i n v e n t o r y i t e m . o main . o : main . cpp i n v e n t o r y i t e m . h
g++ −c main . cpp
i n v e n t o r y i t e m . o : i n v e n t o r y i t e m . cpp i n v e n t o r y i t e m . h g++ −c i n v e n t o r y i t e m . cpp
c l e a n :
rm − f main . o i n v e n t o r y i t e m . o i i
En mer avancerad makefil
CC = g++
FLAGS = −g − I ˜/ l i b s
OBJ = main . o i n v e n t o r y i t e m . o SRC = main . cpp i n v e n t o r y i t e m . cpp PROG = i i
$ (PROG ) : $ (OBJ)
$ (CC) $ ( FLAGS ) −o $ (PROG) $ (OBJ)
%.o : %. cpp
$ (CC) $ ( FLAGS ) −c $ ∗ . cpp c l e a n :
rm − f ∗ . o $ (PROG) d e p e n d : $ ( SRC )
makedepend $ ( FLAGS ) $ ˆ
Programsystemkonstruktion med C++: ¨Ovning 1 Spr˚akfunktionalitet
Preprocessordirektiv
#include sl˚ ar ihop filer innan kompilering
#ifndef ... #define ... #endif garanterar att en fil bara inkluderas en g˚ ang
// may be u s e f u l
#d e f i n e MAX 10000 // d a n g e r o u s
#d e f i n e SQR1 (A) A∗A // l e s s d a n g e r o u s
#d e f i n e SQR2 (A) (A ) ∗ ( A)
Funktionen main
funktionen main ¨ ar speciell kan inte heta n˚ agot annat
argc ¨ ar antalet argument inkl. programmets namn
argv ¨ ar en array av C-str¨ angar med argumenten som gavs till programmet
argv[0] ¨ ar programmets namn (tex /usr/bin/zip eller zip) main ¨ ar en global funktion och inte del av n˚ agon klass
main beh¨ over inte deklareras
Programsystemkonstruktion med C++: ¨Ovning 1 Spr˚akfunktionalitet
Pekare
v o i d f o o ( I n v e n t o r y I t e m ∗ i t ) {
i n t ∗ p t r , i ; // p t r i s p t r t o i n t , i i s i n t i n t ∗ x , y ; // x i s p t r t o i n t , y i s i n t
p t r = & i ; // p t r now h o l d s a d d r e s s o f i ( e . g . 0 x b f f f f f 2 4 )
∗ p t r = 5 ; // a s s i g n 5 t o i
x = p t r ; // x now a l s o p o i n t s t o i c o u t << ∗ x << e n d l ; // w o u l d p r i n t 5 ( ∗ i t ) . r e m o v e U n i t s ( 1 0 ) ;
i t −>r e m o v e U n i t s ( 1 0 ) ;
p t r = new i n t ; // p t r now h o l d s a d r o f i n t on h e a p p t r = &y ; // no way t o a c c e s s memory anymore }
Pekare och arrayer
v o i d f o o ( f l o a t f ) {
c h a r a r r a y [ 4 7 1 1 ] ; // a r r a y o f 4711 u n i n i t i a l i z e d c h a r s i n t a r y [ ] = { 1 , 2 , 5 } ; // a r r a y o f 3 i n i t i a l i z e d i n t s // same a s c o n s t c h a r s t r [ ] = { ’ h ’ , ’ e ’ , ’ j ’ , 0 } ; c h a r s t r [ ] = ” h e j ” ;
c h a r ∗ p t r = 0 ; // c h a r p o i n t e r t o n o t h i n g
c o n s t f l o a t ∗ f P t r ; // memory p o i n t e d t o i s r e a d o n l y f l o a t ∗ c o n s t f c P t r=f ; // p o i n t e r f i s r e a d o n l y p t r = a r r a y ; // same a s p t r = &a r r a y [ 0 ] ;
p t r [ 4 ] = ’ x ’ ; // s e t f i f t h e l e m e n t o f a r r a y t o x
∗ ( p t r + 4 ) = ’ y ’ ; // same t h i n g , b u t t o y
p t r = new c h a r [ 5 1 2 ] ; // d y n a m i c a l l y a l l o c a t e d a r r a y }
Programsystemkonstruktion med C++: ¨Ovning 1 Spr˚akfunktionalitet
Referenser
alias f¨ or ett objekt
som en pekare vars adress inte f˚ ar ¨ andras m˚ aste referera till ett objekt (inte NULL)
v o i d i s w a p ( i n t &i 1 , i n t &i 2 ) {
i n t tmp = i 1 ; i 1 = i 2 ; i 2 = tmp ; }
v o i d main ( ) {
i n t i = 5 ; i n t &i R e f = i ; i n t ∗ i P t r = & i ;
i R e f ++; // i , i R e f and ∗ i P t r i s now 6 }
Vanliga slarvfel
v o i d f o o ( i n t ∗ p ) { d e l e t e p ;
}
i n t ∗ b a r ( ) { i n t x = 1 ;
r e t u r n &x ; // o o p s ! }
v o i d f u n ( ) {
i n t ∗ p1 , p2 ; // p2 i s n o r m a l i n t n o t p o i n t e r i n t ∗ p3 = new i n t [ 2 ] ;
i n t ∗ p4 = new i n t [ 2 ] ; p3 = p4 ; // MEMORY LEAK !
f o o ( p3 ) ; // d e s t r u c t i o n o f p3 ( and p4 ) i n t x = p4 [ 1 ] ; // e r r o r ( s e g f a u l t i f LUCKY) }
Programsystemkonstruktion med C++: ¨Ovning 1 Vanliga problem
Vanliga fel vid kompilering
anrop till funktioner vars headerfil inte inkluderats med
include, f¨ or att anv¨ anda funktionen cout m˚ aste man t ex ha
#include <iostream>
anrop till funktioner i namnrymden std utan att ha deklarerat using namespace std, anrop till cout m˚ aste d˚ a skrivas std::cout
alla objektfiler har inte kompilerats om efter koduppdatering anv¨ andning av C-kompilatorn gcc ist¨ allet f¨ or g++
funktionerna som anv¨ ands har inte deklarerats som public (private ¨ ar f¨ orvalt)
klassdeklarationerna avslutas inte med semikolon
Testning
testning ¨ ar processen att prova vissa av exekveringarna av ett system enligt ett givet kriterie.
enhetstestning ¨ ar processen att testa de minsta
best˚ andsdelarna av ett system (funktioner och klasser) i en isolerad milj¨ o.
N˚ agra anledningar till att testa:
evidens att koden g¨ or vad den ska
m¨ ojligg¨ or omstrukturering med bibeh˚ allen funktionalitet snabbare lokalisering av introducerade buggar
“Testa tidigt. Testa ofta. Testa automatiskt.”
Programsystemkonstruktion med C++: ¨Ovning 1 Testning
Testramverket cxxtest
testramverk f¨ or C++ som bara kr¨ aver kompilator och Python tester skrivs i separat fil—k¨ orbar kod genereras via skript tester organiseras i testsviter (test suites)
i testfunktioner g¨ ors p˚ ast˚ aende med macron som TS ASSERT och TS ASSERT EQUALS
mer information p˚ a http://cxxtest.tigris.org
Exempel p˚ a enhetstester: inventory item test.cpp
#i n c l u d e < c x x t e s t / T e s t S u i t e . h>
#i n c l u d e ” i n v e n t o r y i t e m . h ”
c l a s s I n v e n t o r y I t e m T e s t : p u b l i c C x x T e s t : : T e s t S u i t e {
p u b l i c :
v o i d t e s t d e f a u l t c o s t a n d u n i t s ( v o i d ) {
I n v e n t o r y I t e m i t ;
TS ASSERT EQUALS ( i t . v a l u e ( ) ,
I n v e n t o r y I t e m : : DEF COST ∗ I n v e n t o r y I t e m : : DEF UNITS ) ; }
v o i d t e s t n e g a t i v e c o s t ( v o i d ) {
I n v e n t o r y I t e m i t ( −10 , 1 0 0 ) ; TS ASSERT EQUALS ( i t . v a l u e ( ) , 0 ) ; }
} ;
Programsystemkonstruktion med C++: ¨Ovning 1 Testning
Makefil f¨ or cxxtest
CC = g++
FLAGS = −g
OBJ = i n v e n t o r y i t e m . o t e s t r u n n e r . o PROG = t e s t r u n n e r
$ (PROG ) : $ (OBJ)
$ (CC) $ ( FLAGS ) −o $ (PROG) $ (OBJ)
%.o : %. cpp
$ (CC) $ ( FLAGS ) −c $ ∗ . cpp
t e s t r u n n e r . cpp : i n v e n t o r y i t e m t e s t . cpp i n v e n t o r y i t e m . h c x x t e s t g e n . py −−e r r o r − p r i n t e r −o t e s t r u n n e r . cpp \
i n v e n t o r y i t e m t e s t . cpp c l e a n :
rm − f ∗ . o $ (PROG) t e s t r u n n e r . cpp
Testk¨ orningar
$ make
g++ −g −c i n v e n t o r y i t e m . cpp
c x x t e s t g e n . py −−e r r o r − p r i n t e r −o t e s t r u n n e r . cpp \ i n v e n t o r y i t e m t e s t . cpp
g++ −g −c t e s t r u n n e r . cpp
g++ −g −o t e s t r u n n e r i n v e n t o r y i t e m . o t e s t r u n n e r . o
$ . / t e s t r u n n e r R u n n i n g 2 t e s t s . . OK!
Om cost kan anta negativa v¨ arden:
$ . / t e s t r u n n e r R u n n i n g 2 t e s t s .
I n I n v e n t o r y I t e m T e s t : : t e s t n e g a t i v e c o s t : i n v e n t o r y i t e m t e s t . cpp : 1 5 : E r r o r : E x p e c t e d ( i t . v a l u e ( ) == 0 ) , f o u n d ( − 1 0 0 0 . 0 0 0 0 != 0 ) F a i l e d 1 o f 2 t e s t s
S u c c e s s r a t e : 50%