Programsystemkonstruktion med C++ Övning 2 Daniel Aarno bishop@kth.se
Översikt övning 2 Klasser Konstruktorer Destruktorer Arv Virtuella funktioner Abstrakta klasser Operatorer Templateklasser Templatefunktioner Metaprogrammering Kodningstips Tentatal 2
#ifndef _MOVIE_RECORD_ #define _MOVIE_RECORD_ Klasser class MovieRecord { public: MovieRecord(); MovieRecord(const MovieRecord &mr); MovieRecord(std::string title, std::string director = "", int year = 0); ~MovieRecord(); operator=(const MovieRecord &mr); friend std::ostream& operator<<(const ostream &os, const MovieRecord &mr); protected: //< Not needed private: std::string m_title; std::string m_director; int m_year; ; #endif //_MOVIE_RECORD_ 3
Konstruktorer Minnesallokering automatiskt minne (stacken) dynamiskt minne (heapen) Initiering av medlemmar Styrs via initieringslista (kolonlista) OBS! Följande MÅSTE initieras via kolonlista const-deklarerade medlemmar referenser medlemsvariabler av en typ som saknar defaultkonstruktor Exekvering av kod i konstruktorn 4
Konstruktorer (cont'd) Följande konstruktorer skapas automatiskt Defaultkonstruktor (kör medlemmars defaultkonstruktor) Kopieringskonstruktor (kör medlemmars kopieringskonstruktor) Även kopieringsoperatorn (operator=) skapas automatiskt Kopierar elementvis 5
Konstruktorer (cont'd) #include <iostream> class A { public: std::string str; ; int main() { A a; std::cout << a.str << std::endl; a.str = "Hello"; std::cout << a.str << std::endl; A b(a); std::cout << b.str << std::endl; a.str += World ; b = a; std::cout << b.str << std::endl; 6
Destruktorer Kan bara finnas en destruktor Tar aldrig några argument Defaultdestruktor kör medlemmars destruktor Tänk på att göra delete och/eller delete[] på rätt sätt i destruktorn 7
Arv Animal name: std::string = +getname(): std::string Donkey Horse Mule http://pigseye.kennesaw.edu/~dbraun/ csis4650/a&d/uml_tutorial/ http://www.gnome.org/projects/dia/ 8
Arv (cont'd) Objekt Animal Donkey Mule Konstruktor Animal Animal Donkey Animal Donkey Animal Horse Mule Destruktor ~Animal ~Donkey ~Animal ~Mule ~Horse ~Animal ~Donkey ~Animal 9
Arv (cont'd) class BaseClass { OtherClass& m_ref; const int m_c; public: BaseClass(OtherClass& ref, int c) : m_ref(ref), m_c(c) {; // BaseClass(OtherClass& ref, int c) : // m_c(c), m_ref(ref) {; //< Warning! /*...*/ ; class SubClass: public BaseClass { public: SubClass(OtherClass& ref, int c=4711) : BaseClass(ref,c) {; // SubClass(OtherClass& ref, int c=4711) : // m_ref(ref), m_c(c) {; //< Error! /*...*/ ; 10
Virtuella funktioner class A { void foo() { cout << A::foo() << endl; virtual void bar() { cout << A::bar() << endl; ; class B : public A { void foo() { cout << B::foo() << endl; void bar() { cout << B::bar() << endl; ; int main() { B b, *bptr = &b; A *aptr = bptr; bptr >foo(); bptr >bar(); aptr >foo(); aptr >bar(); return 0; 11
Virtuella funktioner (cont'd) int main() { B b, *bptr = &b; A *aptr = bptr; bptr >foo(); bptr >bar(); aptr >foo(); aptr >bar(); return 0; >./a.out B::foo() B::bar() A::foo() B::bar() 12
Virtuella funktioner (cont'd) 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. class A { void foo() { cout << A::foo() << endl; virtual void bar() { cout << A::bar() << endl; ; class B : public A { void foo() { cout << B::foo() << endl; void bar() { cout << B::bar() << endl; ; 13
Virtuella funktioner (cont'd) Class int m_id; std::string name;... v table {... *func1; *func2;... *funcn; V-table 14
Virtuella funktioner (cont'd) Virtuella destruktorer Vad är problemet med följande kod? class A { public: ~A(){ cout << "~A()" << endl; ; class B : public A { public: ~B(){cout << "~B()" << endl; ; int main() { A* a = new A(); A* b = new B(); delete a; delete b; 15
Virtuella funktioner (cont'd) Det går ej att skapa en instans av en klass som är "abstrakt". För att göra en klass abstrakt, låt någon funktion i klassen vara "rent" virtuell (pure virtual). Ex: class A { public: virtual foo() = 0;... ; Klasser som ärver av basklassen MÅSTE implementera de funktioner som är "pure virtual" för att man ska kunna instantiera ett objekt av klassen (annars blir ju även subklassen abstrakt). 16
Virtuella funktioner (cont'd) C++ Virtual virtual void func(); Pure virtual virtual void func() = 0; Java Default void func(); Abstract abstract void func(); 17
Operatorer class Vec { int *m_elem; public: Vec(){m_elem = new int[10]; ~Vec() { delete[] m_elem; ; int main(){ Vec v1; Vec v2(v1); Vec v3; v3=v2; ; Vec::v1 m_elem Vec::v2 m_elem Vec::v3 m_elem Minne 18
Operatorer class Vec { int *m_elem; public: Vec(){m_elem = new int[10]; ~Vec() { delete[] m_elem; Vec::v1 m_elem Vec(const Vec& v) { m_elem = new int[10]; for(int i=0; i<10; i++) m_elem[i] = v.m_elem[i]; Vec::v2 m_elem Minne ; Vec& operator=(const Vec& v) { if(this!=&v){ delete[] m_elem; m_elem = new int[10]; for(int i=0; i<10; i++) m_elem[i] = v.m_elem[i]; return *this; Vec::v3 m_elem 19
Operatorer (cont'd) class Complex { float m_re; float m_im; public: Complex(float re = 0, float im = 0); Complex(const Complex &c); ~Complex(); Complex& operator=(const Complex &c); Complex& operator++(); //prefix Complex& operator++(int); //postfix Complex& operator (); //prefix Complex& operator (int); //postfix Complex& operator+=(const Complex &c); Complex& operator =(const Complex &c); Complex& operator*=(const Complex &c); bool operator==(const Complex &c) const; bool operator!=(const Complex &c) const; friend Complex operator+(const Complex &c1, const Complex &c2); friend Complex operator (const Complex &c1, const Complex &c2); friend ostream& operator<<(ostream &os, const Complex &c); ; 20
Templateklasser class Stack { private: int m_stk[stk_size]; int m_top; public: Stack() : m_top(0) {; bool isempty() { return (m_top == 0); bool isfull() { return (m_top >= STK_SIZE); bool push(int i) { if(isfull()) return false; m_stk[m_top++] = i; return true; bool pop(int &i) { if(isempty()) return false; i = m_stk[ m_top]; return true; ; 21
Templateklasser (cont'd) template <typename T> class Stack { private: T m_stk[stk_size]; int m_top; public: Stack() : m_top(0) {; bool isempty() { return (m_top == 0); bool isfull() { return (m_top >= STK_SIZE); bool push(const T &o) { if(isfull()) return false; m_stk[m_top++] = o; return true; bool pop(t &o) { if(isempty()) return false; o = m_stk[ m_top]; return true; ; 22
Templateklasser (cont'd) int main() { Stack<int> istk; //< Stack of ints Stack<double> fstk; //< Stack of doubles istk.push(4711); istk.push(47.11); //< Will be truncated to 47 (Warning) fstk.push(47.11); fstk.push(4711); //< Will be represented as (double)4711 return 0; 23
Templatefunktioner (cont'd) template<typename T> inline T max(const T &o1, const T &o2) { return o1 > o2? o1 : o2; template<> const char* max<char*>(const char* &o1, const char* &o2) { return strcmp(o1,o2) >= 0? o1 : o2; int main() { max(3,6); max(3.2, 0.3); //max(3, 3.2); //< Error max<double>(3, 3.2); //< OK max( Hejsan, Svejsan ); return 0; 24
Templatefunktioner (cont'd) Vid kompilering av templates måste alla templatefunktioner och klasser vara definierade innan de används. Detta medför att templatefunktioner och klasser oftast definieras i.h-filen. main.cpp #include Stack.h int main() { Stack<int> istk; //... return 0; > g++ main.cpp o stktst >./stktst Stack.cpp finns inte, implementation i.h-filen 25
Templatefunktioner (cont'd) Templates Återanvända kod (+) Statisk typkontroll (+) Effektiv implementering (+) Måste definieras innan användning (-) Långsam kompilering (-) Stor binärfil (-) Arv från Object (Java) Återanvända kod (+) Flexibelt (man kan t ex blanda objekt i en vektor) (+) Run-time typkontroll (-) Overhead pga V-table etc (-) Allt måste ärva från ett objekt (-) 26
Metaprogrammering template<int N> struct fact { enum{value=n*fact<n 1>::value; ; template<> struct fact<0> { enum{value=1; ; int main() { cout<< fact<3>::value << endl; return 0; 27
Kodningstips Var konsekvent Ge klasser, funktioner och publika medlemsvariabler beskrivande namn En klass, två filer (.h och.cpp) Undvik altför smart kod Indentera ordentligt Undvik one-line-ifs, använd { Undvik nästlade if/for satser Skriv inte för långa funktioner, dela upp 28
Kodningstips Förslag på namngivning Globala variabler: longvarname Medlemsvariabler: varnam Lokala variabler: tmp, i, cnt, f,... Konstanter: CONST_NAME Klasser: LongClassName Medlemsfunktioner: longfuncname Globala funktioner: LongFuncName Statiska medlemsfunktioner: LongFuncName 29