Programsystem konstruktion med C++ (2D1387) övning 2 klasser och arv Ronnie Johansson rjo@nadakthse grupp 4 2003 09 25 Innehåll Klasskonstruktorer och initieringslistor Klassdestruktorer Åtkomstkontroll medlemmar är public, protected eller private Arv även arv kan vara public, protected eller private Multipelt arv ej möjligt i Java Virtuella funktioner, överlagring (override), polymorfism Abstrakta basklasser Const deklarerade medlemmar och metoder Konstruktorer Objekt skapas 3 stegsraket: 1: Minnesallokering automatiskt minne dynamiskt minne 2: Initiering av medlemmar Styrs via initieringslista (kolonlista) OBS! Följande MÅSTE initieras via kolonlistan const deklarerade medlemmar referenser 3: Exekvering av kod i konstruktorn (funktionskroppen) Student(std::string name) : m_name(name) m_lectures = new (Lecture*)[100]; const std::string name; Lecture **m_lectures; ; "Automatiska" konstruktorer Följande konstruktorer skapas automatiskt defaultkonstruktor kopieringskonstruktor std::string str; int main() A a; astr = "Hallå världen!"; std::cout << astr << std::endl; A b(a); std::cout << bstr << std::endl; Även kopieringsoperatorn skapas "automatiskt" int main() A a; astr = "Hallå igen!"; A b; b = a; std::cout << b << std::endl;
Direkt och indirekt användning av konstruktorer Default och kopieringskonstruktörerna skapas automatisk // Defaultkonstruktorn default constructor A(); // Kopieringskonstruktorn copy constructor A(const A&); Även kopieringsoperatorn skapas automatiskt: // kopiering copy assignment A& operator=(const &A); main () A a1; A a2 = 2; A a3 = a1; a1 = a2; Indirekt typkonvertering class One One() ; class Two Two(One)//konstruktor ; void f(two) int main() One one; f(one); // Vill ha Two, har One Begränsning av användning av konstruktorer För att förhindra användning av konstruktor A(const A&);// behövs ej // definieras För att undvika indirekt typkonvertering explicit A(int); Destruktorer Student(std::string name); ~Student(); const std::string name; Lecture **m_lectures; ; Student::Student(std::string name) : m_name(name) m_lectures = new (Lecture*)[100]; for(int i = 0; i < 100; ++i) m_lectures[i] = 0; Student::~Student() for(int i = 0; i < 100; ++i) if(m_lectures[i]!= 0) delete m_lectures[i]; delete [] m_lectures;
Arv: konstruktorer & destruktorer class ()cout << "" << endl; ~()cout << ~" << endl; class : public class : public Begränsat arv Class B : public/protected/private A class Mule : public, public int main() *a = new (); *h = new (); *d = new ; Mule *m = new Mule(); delete a; delete h; delete d; delete m; Konstruktor Destruktor ~ ~ ~ ~ ~ Mule Mule ~Mule ~ ~ ~ ~ Virtuella funktioner och polymorfism Funktioner i klasser måste vara deklarerade som virtual för att vi ska kunna använda pekare till basklass foo()cout << "A::foo()" << endl; ; Non virtual vs virtual 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 B : public A foo()cout << "B::foo()" << endl; ; int main() A *b = new B(); b >foo(); Dator>prog a::foo() Class: int m_id std::string name v table V table *func1 *func2 *func3
Virtuella destruktorer Vad är problemet med följande kod? cout << "" << endl; ; class B : public A ~B()cout << "~B()" << endl; ; int main(int argc, char *argv[]) A* a = new A(); A* b = new B(); delete a; delete b; Dator> prog Lösning! virtual cout << "~AV()" << endl; ; Dator> prog ~B() Abstrakta klasser Det går ej att skapa instans av 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: virtual Student() = 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 Motsvarar "interface" i Java Class Shape virtual void draw() = 0; class Box : public Shape class Circle : public Shape vector<shape *> v; v[1] = new Box(); v[2] = new Circle(); s = v[1]; s >draw(); s = v[2]; s >draw(); Statiska variabler & funktioner Exempel: Singelton klass class Singleton static Singleton& get_instance(); Singleton(); Singleton(const Singleton &s); Singleton& operator=(const Singleton &s); static Singleton *m_instance; ; Singleton* Singleton::m_instance = 0; Singleton& Singleton::get_instance() if(m_instance == 0) m_instance = new Singleton(); return *m_singleton; Operatoröverlagring Varför? Man vill till exmpel kunna skriva: Matrix m3=m1+m2; och överlagra utskriftsoperatorn << 42 operatorer kan överlagras bl a: +, =, <<, ++ (både postfix och prefix), >, (), new, 3 operatorer kan ej överlagras av användaren: ::, och * Självreferens class Complex double re, im; Complex& Complex::operator+=(const Complex c) re += cre; im += cim; return *this;
Exempel: Counter (studenth) Student(std::string name); Student(const Student &s); Student(); static int m_counter; std::string name; int m_student_id; ; (studentcpp) int Student::m_counter = 0; Student::Student(std::string name) : m_name(name), m_id(++m_counter) Student::Student(const Student &s) : m_name(sget_name()), m_id(++m_counter) (maincpp) Student s1("kalle"); Student s2("lotta"); std::cout << s1get_id() << std::endl; std::cout << s2get_id() << std::endl;