Daniel Aarno
bishop@kth.se
Programsystemkonstruktion med C++
Övning 2
Översikt övning 2
Klasser
Konstruktorer Destruktorer Arv
Virtuella funktioner Abstrakta klasser
Operatorer
Templateklasser
Templatefunktioner Metaprogrammering Kodningstips
Tentatal
2
#ifndef _MOVIE_RECORD_
#define _MOVIE_RECORD_
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_
Klasser
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
Mule
Donkey Horse
http://www.gnome.org/projects/dia/
http://pigseye.kennesaw.edu/~dbraun/
csis4650/A&D/UML_tutorial/
8
Arv (cont'd)
Konstruktor
Animal Animal Donkey Animal Donkey Animal Horse Mule
Destruktor
~Animal
~Donkey
~Animal
~Mule
~Horse
~Animal
~Donkey
~Animal
Objekt
Animal Donkey
Mule
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)
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; } };
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.
13
Virtuella funktioner (cont'd)
Class
int m_id;
std::string name;
...
vtable {...}
V-table
*func1;
*func2;
...
*funcN;
14
Virtuella funktioner (cont'd)
Virtuella destruktorer
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;
}
Vad är problemet med följande kod?
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
M inne
18
Operatorer
class Vec {
int *m_elem;
public:
Vec(){m_elem = new int[10];}
~Vec() { delete[] 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& 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::v1 m_elem Vec::v2 m_elem Vec::v3 m_elem
M inne
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;
}
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;
}
template<>
const char* max<char*>(const char* &o1, const char* &o2) {
return strcmp(o1,o2) >= 0 ? o1 : o2;
}
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.
#include ”Stack.h”
int main() {
Stack<int> istk;
//...
return 0;
}
> g++ main.cpp o stktst
> ./stktst main.cpp