Föreläsningsanteckningar OOP-föreläsning 9, måndag 2 oktober 2006 ================================================================= Idag ==== 1. Information om information i morgon 2. Kvar från förra gången: En vektorklass i form av en mall (template) 3. Kvar från förra gången: operator[] 4. En vektor-"klass" i C 5. Egna typkonverteringar: operator double 6. Geometriska figurer, enkelt och fel 7. Geometriska figurer, med virtuella funktioner 8. Kan ni hitta felet? Och vad händer? 9. Ett problem inom objektorientering 2. Kvar från förra gången: En vektorklass i form av en mall (template) ====================================================================== vektor-2.cpp ------------ #include using namespace std; template class Vektor { private: T* lagring; int storlek; public: Vektor(int storlek); Vektor(const Vektor& original); ~Vektor(); const Vektor& operator=(const Vektor& original); }; template Vektor::Vektor(int storlek) { this->storlek = storlek; lagring = new T[storlek]; } template Vektor::Vektor(const Vektor& original) { this->storlek = original.storlek; lagring = new T[original.storlek]; for (int i = 0; i < storlek; ++i) lagring[i] = original.lagring[i]; } template Vektor::~Vektor() { delete [] lagring; } template const Vektor& Vektor::operator=(const Vektor& original) { if (this != &original) { delete [] lagring; this->storlek = original.storlek; lagring = new T[original.storlek]; for (int i = 0; i < storlek; ++i) lagring[i] = original.lagring[i]; } return *this; } int main() { Vektor v1(3); Vektor v2 = 7; Vektor v3 = v1; v2 = v1; Vektor v4(10); } 3. Kvar från förra gången: operator[] ===================================== Användning ---------- Vektor v(3); v[0] = 7.1; v[2] = 5.9; cout << "v[0] == " << v[0] << endl; cout << "v[1] == " << v[1] << endl; Deklaration i klassdefinitionen ------------------------------- T& Vektor::operator[](int i); Definition ---------- template T& Vektor::operator[](int i) { return lagring[i]; } 4. En vektor-"klass" i C ======================== vektor.h -------- #ifndef VEKTIOR_H #define VETKTOR_H struct Vektor { double* lagring; int storlek; }; typedef struct Vektor Vektor; extern void vektor_init(struct Vektor* this, int storlek); extern void vektor_copy(struct Vektor* this, struct Vektor* original); extern void vektor_cleanup(struct Vektor* this); extern double vektor_get(struct Vektor* this, int pos); extern void vektor_set(struct Vektor* this, int pos, double value); #endif vektor.c -------- #include #include "vektor.h" void vektor_init(struct Vektor* this, int storlek) { this->storlek = storlek; this->lagring = malloc(storlek * sizeof(double)); } void vektor_cleanup(struct Vektor* this) { free(this->lagring); } double vektor_get(struct Vektor* this, int pos) { return this->lagring[pos]; } void vektor_set(struct Vektor* this, int pos, double value) { this->lagring[pos] = value; } main.c ------ #include #include #include "vektor.h" int main() { Vektor v; vektor_init(&v, 3); vektor_set(&v, 0, 7.1); vektor_set(&v, 2, 5.9); printf("v[0] == %f\n", vektor_get(&v, 0)); printf("v[1] == %f\n", vektor_get(&v, 1)); vektor_cleanup(&v); return 0; } 5. Egna typkonverteringar: operator double ========================================== komplex-3.cpp ------------- #include using namespace std; class KOMPLEX { private: double re, im; public: KOMPLEX(double re, double im); KOMPLEX(); KOMPLEX operator+(KOMPLEX k2); KOMPLEX operator-(KOMPLEX k2); KOMPLEX operator*(KOMPLEX k2); KOMPLEX operator/(KOMPLEX k2); operator double(); operator int(); friend ostream& operator<<(ostream& ut, KOMPLEX& p); }; KOMPLEX::KOMPLEX(double re, double im) { this->re = re; this->im = im; } KOMPLEX::KOMPLEX() { this->re = 0; this->im = 0; } KOMPLEX KOMPLEX::operator+(KOMPLEX k2) { KOMPLEX temp; temp.re = this->re + k2.re; temp.im = this->im + k2.im; return temp; } KOMPLEX KOMPLEX::operator-(KOMPLEX k2) { KOMPLEX temp; temp.re = this->re + k2.re; temp.im = this->im + k2.im; return temp; } KOMPLEX KOMPLEX::operator*(KOMPLEX k2) { // ... } KOMPLEX KOMPLEX::operator/(KOMPLEX k2) { // ... } KOMPLEX::operator double() { return re; } KOMPLEX::operator int() { return (int)re; } ostream& operator<<(ostream& ut, KOMPLEX& k) { if (k.im < 0) cout << "(" << k.re << " - " << -k.im << "i)"; else cout << "(" << k.re << " + " << k.im << "i)"; return cout; } int main() { KOMPLEX z(1.13, 0.9); cout << "z = " << z << endl; cout << "(double)z = " << (double)z << endl; cout << "(int)z = " << (int)z << endl; double d; d = (double)z; cout << "d = " << d << endl; d = z; cout << "d = " << d << endl; int i; i = (int)z; cout << "i = " << i << endl; i = z; cout << "i = " << i << endl; } Utmatning --------- z = (1.13 + 0.9i) (double)z = 1.13 (int)z = 1 d = 1.13 d = 1.13 i = 1 i = 1 (Vad händer om man tar bort operator int?) 6. Geometriska figurer, enkelt och fel ====================================== figurer-1.cpp ------------- #include #include using namespace std; //---------------------------------------------------------- class FIGUR { private: string namn; public: FIGUR(string namn); void skriv(); }; FIGUR::FIGUR(string namn) { this->namn = namn; } void FIGUR::skriv() { cout << "Namn: " << namn << endl; } //---------------------------------------------------------- class REKTANGEL : public FIGUR { private: double bredd, hojd; public: REKTANGEL(string namn, double bredd, double hojd); void skriv(); double area(); }; REKTANGEL::REKTANGEL(string namn, double bredd, double hojd) : FIGUR(namn) { this->bredd = bredd; this->hojd = hojd; } double REKTANGEL::area() { return bredd * hojd; } void REKTANGEL::skriv() { FIGUR::skriv(); cout << "Bredd: " << bredd << ", höjd: " << hojd << endl; } //---------------------------------------------------------- class CIRKEL : public FIGUR { private: double radie; static const double PI = 3.1415926535; public: CIRKEL(string namn, double radie); void skriv(); double area(); }; CIRKEL::CIRKEL(string namn, double radie) : FIGUR(namn) { this->radie = radie; } double CIRKEL::area() { return PI * radie * radie; } void CIRKEL::skriv() { FIGUR::skriv(); cout << "Radie: " << radie << endl; } //---------------------------------------------------------- class KVADRAT : public REKTANGEL { public: KVADRAT(string namn, double sida); void skriv(); }; KVADRAT::KVADRAT(string namn, double sida) : REKTANGEL(namn, sida, sida) { } void KVADRAT::skriv() { FIGUR::skriv(); cout << "Sida: " << sqrt(area()) << endl; // sqrt, eftersom sidomåtten är privata i REKTANGEL } //---------------------------------------------------------- int main() { FIGUR f1("f1"); FIGUR hjalmar("hulda"); f1.skriv(); REKTANGEL r1("r1", 10, 17.3); r1.skriv(); cout << "r1:s area = " << r1.area() << endl; CIRKEL c1("c1", 10); c1.skriv(); cout << "c1:s area = " << c1.area() << endl; KVADRAT k1("k1", 10); k1.skriv(); cout << "k1:s area = " << k1.area() << endl; KVADRAT* k2p = new KVADRAT("k2", 12.5); k2p->skriv(); cout << "k2:s area = " << k2p->area() << endl; FIGUR* k3p = new KVADRAT("k3", 12.5); // Här anropas fel skriv-funktion, eftersom "skriv" inte är virtuell: k3p->skriv(); // Funkar inte, eftersom "area" inte är virtuell i FIGUR: // cout << "k3:s area = " << k3p->area() << endl; } Utmatning --------- Namn: f1 Namn: r1 Bredd: 10, höjd: 17.3 r1:s area = 173 Namn: c1 Radie: 10 c1:s area = 314.159 Namn: k1 Sida: 10 k1:s area = 100 Namn: k2 Sida: 12.5 k2:s area = 156.25 Namn: k3 7. Geometriska figurer, med virtuella funktioner ================================================ figurer-2.cpp ------------- #include #include using namespace std; //---------------------------------------------------------- class FIGUR { private: string namn; FIGUR* next; static FIGUR* first; public: FIGUR(string namn); virtual void skriv(); virtual double area() = 0; FIGUR* get_next(); static double total_area(); }; FIGUR* FIGUR::first = NULL; FIGUR::FIGUR(string namn) { this->namn = namn; next = first; first = this; } void FIGUR::skriv() { cout << "Namn: " << namn << endl; } double FIGUR::total_area() { FIGUR* p = first; double summa = 0; while (p != NULL) { summa += p->area(); p = p->next; } return summa; } //---------------------------------------------------------- class REKTANGEL : public FIGUR { private: double bredd, hojd; public: REKTANGEL(string namn, double bredd, double hojd); void skriv(); double area(); }; REKTANGEL::REKTANGEL(string namn, double bredd, double hojd) : FIGUR(namn) { this->bredd = bredd; this->hojd = hojd; } double REKTANGEL::area() { return bredd * hojd; } void REKTANGEL::skriv() { FIGUR::skriv(); cout << "Bredd: " << bredd << ", höjd: " << hojd << endl; } //---------------------------------------------------------- class CIRKEL : public FIGUR { private: double radie; static const double PI = 3.1415926535; public: CIRKEL(string namn, double radie); void skriv(); double area(); }; CIRKEL::CIRKEL(string namn, double radie) : FIGUR(namn) { this->radie = radie; } double CIRKEL::area() { return PI * radie * radie; } void CIRKEL::skriv() { FIGUR::skriv(); cout << "Radie: " << radie << endl; } //---------------------------------------------------------- class KVADRAT : public REKTANGEL { public: KVADRAT(string namn, double sida); void skriv(); }; KVADRAT::KVADRAT(string namn, double sida) : REKTANGEL(namn, sida, sida) { } void KVADRAT::skriv() { FIGUR::skriv(); cout << "Sida: " << sqrt(area()) << endl; // sqrt, eftersom sidomåtten är privata i REKTANGEL } //---------------------------------------------------------- int main() { // FIGUR f1("f1"); -- Går inte, för FIGUR är en abstrakt klass REKTANGEL r1("r1", 10, 17.3); r1.skriv(); cout << "r1:s area = " << r1.area() << endl; CIRKEL c1("c1", 10); c1.skriv(); cout << "c1:s area = " << c1.area() << endl; KVADRAT k1("k1", 10); k1.skriv(); cout << "k1:s area = " << k1.area() << endl; KVADRAT* k2p = new KVADRAT("k2", 12.5); k2p->skriv(); cout << "k2:s area = " << k2p->area() << endl; FIGUR* k3p = new KVADRAT("k3", 12.5); k3p->skriv(); cout << "k3:s area = " << k3p->area() << endl; cout << "Sammanlagda arean = " << FIGUR::total_area() << endl; } Utmatning --------- Namn: r1 Bredd: 10, höjd: 17.3 r1:s area = 173 Namn: c1 Radie: 10 c1:s area = 314.159 Namn: k1 Sida: 10 k1:s area = 100 Namn: k2 Sida: 12.5 k2:s area = 156.25 Namn: k3 Sida: 12.5 k3:s area = 156.25 8. Kan ni hitta felet? Och vad händer? ====================================== void KVADRAT::skriv() { FIGUR:skriv(); cout << "Sida: " << sqrt(area()) << endl; } Varning från kompilatorn ------------------------ figurer-1.cpp: In member function `void KVADRAT::skriv()': figurer-1.cpp:85: warning: label `FIGUR' defined but not used 9. Ett problem inom objektorientering ===================================== Är en kvadrat verkligen en rektangel?