Programsystemkonstruktion med C++: Övning 2 Karl Palmskog palmskog@kth.se september 2010
Specalfunktioner i klasser Konstruktorer i konstruktorerna för en klass initieras klassens medlemmar initialvärden kan ges i kolonlista eller i kodblock deklareras konstruktorn inte används en förvald förvald konstruktor kör medlemmars förvalskonstruktor kopieringskonstruktorn tar en instans av klassen som argument finns förvald kopieringskonstruktor som kopierar medlemmarna c l a s s V e h i c l e { p r i v a t e : i n t w e i g h t ; p u b l i c : V e h i c l e ( i n t w) : w e i g h t (w) { ;
Specalfunktioner i klasser Destruktorer finns bara en destruktor som inte tar några argument om ej definierad finns förvald destruktor förvald destruktor kör medlemmars destruktor Person : : Person ( ) { // f r e e up memory f o r a r r a y o f heap a l l o c a t e d s k i l l s d e l e t e [ ] s k i l l s ;
Specalfunktioner i klasser Tilldelningsoperatorer och Rule of Three vid tilldelning av variabel till klassinstans anropas tilldelningsoperatorfunktionen operator= den förvalda operator= kopierar medlemmarna tumregler: 1 om du behöver definiera destruktor behöver du definiera kopieringskonstruktor och operator= 2 om du behöver definiera kopieringskonstruktor behöver du definiera destruktor och operator= 3 om du behöver definiera operator= behöver du definiera destruktor och kopieringskonstruktor destruktor, kopieringskonstruktor och operator= hör ihop
Specalfunktioner i klasser #i n c l u d e <i o s t r e a m > c l a s s Foo { p r i v a t e : i n t a ; p u b l i c : Foo ( ) { s t d : : cout << d e f a u l t c o n s t r u c t o r << s t d : : e n d l ; Foo ( const Foo &o t h e r ) { s t d : : cout << copy c o n s t r u c t o r << s t d : : e n d l ; a = o t h e r. a ; Foo ( ) { s t d : : cout << d e s t r u c t o r << s t d : : e n d l ; Foo &operator=(const Foo &o t h e r ) { s t d : : cout << a s s i g n m e n t o p e r a t o r << s t d : : e n d l ; a = o t h e r. a ; r e t u r n t h i s ; ;
Specalfunktioner i klasser Exempel på användning av specialfunktioner #i n c l u d e f o o. h i n t main ( i n t argc, const char a r g v [ ] ) { Foo a ; Foo b ( a ) ; Foo c = a ; Foo d ; d = a ; r e t u r n 0 ;
Specalfunktioner i klasser En arvshierarki Animal string name Donkey Horse Mule
Specalfunktioner i klasser Specialfunktioner och arv Objekt Konstruktor Destruktor Animal Animal Animal Donkey Animal Donkey Donkey Animal Horse Animal Horse Horse Animal Mule Animal Mule Donkey Horse Animal Animal Horse Donkey Mule Animal
Virtuella funktioner Virtuella funktioner icke virtuella funktioner väljs statiskt vid kompilering beroende på typ av pekare eller referens virtuella funktioner bestäms dynamiskt under exekvering baserat på objektets faktiska typ #i n c l u d e <i o s t r e a m > using namespace s t d ; c l a s s A { p u b l i c : void f o o ( ) { cout << A : : f o o ( ) << e n d l ; v i r t u a l void bar ( ) { cout << A : : bar ( ) << e n d l ; ; c l a s s B : p u b l i c A { p u b l i c : void f o o ( ) { cout << B : : f o o ( ) << e n d l ; void bar ( ) { cout << B : : bar ( ) << e n d l ; ;
Virtuella funktioner Virtuella funktioner i praktiken #i n c l u d e ab. h i n t main ( ) { B b ; B bptr = &b ; A aptr = bptr ; bptr >f o o ( ) ; bptr >bar ( ) ; aptr >f o o ( ) ; aptr >bar ( ) ; r e t u r n 0 ; $. / a. out B : : f o o ( ) B : : bar ( ) A : : f o o ( ) B : : bar ( )
Virtuella funktioner Implementation av virtuella funktioner Mule v-table {... V-table *func1 *func2
Virtuella funktioner Virtuella destruktorer Vad är problemet med följande kod? c l a s s A { p u b l i c : A( ) { s t d : : cout << A( ) << s t d : : e n d l ; ; c l a s s B : p u b l i c A { p u b l i c : B( ) { s t d : : cout << B( ) << s t d : : e n d l ; ; i n t main ( ) { A a = new A ( ) ; A b = new B ( ) ; d e l e t e a ; d e l e t e b ;
Virtuella funktioner Pure virtual-funktioner om en funktion är pure virtual måste den implementeras av ärvande klasser motsvarar abstrakta metoder i Java c l a s s A { p u b l i c : v i r t u a l i n t f o o ( ) = 0 ;... ; c l a s s B : p u b l i c A { p u b l i c : v i r t u a l i n t f o o ( ) {...... ;
templates (mallar) används för att skriva typoberoende kod ett alternativ till arv för delade beteenden funktioner och klasser parametriseras på en given typ kompilatorn ersätter förekomster av typparametern och skapar parameterfri funktion/klass
c l a s s Stack { p r i v a t e : s t a t i c const i n t STK SIZE = 1 0 0 ; i n t m stk [ STK SIZE ] ; i n t m top ; p u b l i c : Stack ( ) : m top ( 0 ) { bool isempty ( ) { r e t u r n ( m top == 0 ) ; bool i s F u l l ( ) { r e t u r n ( m top >= STK SIZE ) ; bool push ( i n t v a l ) { i f ( i s F u l l ( ) ) r e t u r n f a l s e ; m stk [ m top++] = v a l ; r e t u r n true ; bool pop ( i n t &v a l ) { i f ( isempty ( ) ) r e t u r n f a l s e ; v a l = m stk[ m top ] ; r e t u r n true ; ;
template <typename T> c l a s s Stack { p r i v a t e : s t a t i c const i n t STK SIZE = 1 0 0 ; T m stk [ STK SIZE ] ; i n t m top ; p u b l i c : Stack ( ) : m top ( 0 ) { bool isempty ( ) { r e t u r n ( m top == 0 ) ; bool i s F u l l ( ) { r e t u r n ( m top >= STK SIZE ) ; bool push ( const T &v a l ) { i f ( i s F u l l ( ) ) r e t u r n f a l s e ; m stk [ m top++] = v a l ; r e t u r n true ; bool pop (T &v a l ) { i f ( isempty ( ) ) r e t u r n f a l s e ; v a l = m stk[ m top ] ; r e t u r n true ; ;
Användning av templatiserad klass #i n c l u d e <i o s t r e a m > #i n c l u d e s t a c k. h i n t main ( ) { Stack<i n t > i s t k ; // s t a c k o f i n t Stack<double> f s t k ; // s t a c k o f d o u b l e s i s t k. push ( 4 7 1 1 ) ; i s t k. push ( 4 7. 1 1 ) ; f s t k. push ( 4 7. 1 1 ) ; f s t k. push ( 4 7 1 1 ) ; i n t i t o p ; i s t k. pop ( i t o p ) ; s t d : : cout << i t o p << s t d : : e n d l ; r e t u r n 0 ;
En typparametriserad maxfunktion Tentauppgift: skriv en typparametriserad funktion max som returnerar det största av två argument. template<typename T> const & T max ( const T & x, const T & y ) { i f ( x < y ) { r e t u r n y ; e l s e { r e t u r n x ; Följdfrågor: vad kräver din typparametriserade funktion av argumenten? varför är returtypen en referens? varför kan man inte ge argument av olika typer?
Metaprogrammering med templates #i n c l u d e <i o s t r e a m > template<i n t N> s t r u c t f a c t { enum { v a l u e = N f a c t <N 1>:: v a l u e ; ; template<> s t r u c t f a c t <0> { enum { v a l u e = 1 ; ; i n t main ( ) { s t d : : cout << f a c t <5>:: v a l u e << s t d : : e n d l ; r e t u r n 0 ;
Kompilering av templatiserade klasser och funktioner templateklasser/funktioner måste vara definierade innan de används normalt sker därför både deklaration och definition i.h-filen kompilatorn behöver då inte ges namnet på klassfilen stöd för separation av definition/deklaration varierar mellan kompilatorer
Templatisering vs. gemensam superklass Gemensam superklass + återanvändning av kod + återanvändning av kod + statisk typkontroll + flexibilitet + effektiv implementation - typkontroll vid körningstid - definition innan användning - overhead - långsam kompilering - stor binärfil
Kodningstips ge klasser, funktioner och medlemmar beskrivande namn dela upp klassdeklarationer och -definitioner i två filer indentera ordentligt undvik enraders if-satser, använd alltid { och undvik om möjligt nästlade if/for satser skriv inte för långa funktioner, dela upp versionshantera all kod med program som mercurial och git använd testramverk och skriv om möjligt testerna innan koden
Namngivningstips globala variabler: longvarname medlemsvariabler: varnam lokala variabler: tmp, i, cnt, f,... konstanter: CONST NAME klasser: LongClassName medlemsfunktioner: longfuncname globala funktioner: LongFuncName statiska medlemsfunktioner: LongFuncName