Föreläsningsanteckningar OOP-föreläsning 7, måndag 24 september 2007 ==================================================================== Idag ==== 1. Kvar från förra gången: Nyckelordet "override" i C++/CLI 2. Operatorer och operatoröverlagring: Komplexa tal med +, - osv 3. I/O med << och >>: operator<< och operator>> 4. En enkel personklass 5. Pekare till en egen resurs 6. Destruktor 7. Man kan skriva ut saker för att se vad som händer 8. Copy-constructor, default-konstruktor, operator= 9. Pekare till en extern resurs 1. Kvar från förra gången: Nyckelordet "override" i C++/CLI ==================================================================== visual-djur2.cpp ---------------- #include "stdafx.h" ref class Djur abstract { public: virtual void ljud() = 0; }; ref class Katt : public Djur { public: virtual void ljud() override; }; ref class Hund : public Djur { public: virtual void ljud() override; }; void Katt::ljud() { System::Console::WriteLine("Mjau!"); } void Hund::ljud() { System::Console::WriteLine("Vov!"); } int main() { // Djur^ d = gcnew Djur; -- Går inte! Djur^ k1 = gcnew Katt; Katt^ k2 = gcnew Katt; Hund^ h = gcnew Hund; // d->ljud(); k1->ljud(); k2->ljud(); h->ljud(); } 2. Operatorer och operatoröverlagring: Komplexa tal med +, - osv ================================================================ Så här kan vi göra (med en inbyggd datatyp, som heltal) ------------------------------------------------------- int main() { int a = 1, b(-2), c; c = a * b / (a + b); cout << a << endl; cin >> b >> c; cout << a << b << c << endl; } Så här vill vi också kunna göra (med en egen datatyp, som KOMPLEXA TAL) ----------------------------------------------------------------------- int main() { KOMPLEX a(1, 0), b(1, -2), c; c = a * b / (a + b); cout << a << endl; cin >> b >> c; cout << a << b << c << endl; } komplex-1.cpp ------------- #include using namespace std; class KOMPLEX { private: double re, im; public: KOMPLEX(double re, double im); KOMPLEX(); KOMPLEX add(KOMPLEX k2); KOMPLEX sub(KOMPLEX k2); KOMPLEX mul(KOMPLEX k2); KOMPLEX div(KOMPLEX k2); KOMPLEX operator+(KOMPLEX k2); KOMPLEX operator-(KOMPLEX k2); KOMPLEX operator*(KOMPLEX k2); KOMPLEX operator/(KOMPLEX k2); }; KOMPLEX::KOMPLEX(double re, double im) { this->re = re; this->im = im; } KOMPLEX::KOMPLEX() { this->re = 0; this->im = 0; } KOMPLEX KOMPLEX::add(KOMPLEX k2) { KOMPLEX temp; temp.re = this->re + k2.re; temp.im = this->im + k2.im; return temp; } KOMPLEX KOMPLEX::sub(KOMPLEX k2) { KOMPLEX temp; temp.re = this->re - k2.re; temp.im = this->im - k2.im; return temp; } KOMPLEX KOMPLEX::mul(KOMPLEX k2) { // ... } KOMPLEX KOMPLEX::div(KOMPLEX k2) { // ... } 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) { // ... } int main() { KOMPLEX a(1, 0), b(1, -2), c; c = a.mul(b).div(a.add(b)); c = a * b / (a + b); } 3. I/O med << och >>: operator<< och operator>> =============================================== komplex-2.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); friend ostream& operator<<(ostream& ut, KOMPLEX& k); friend istream& operator>>(istream& in, KOMPLEX& k); }; 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) { // ... } ostream& operator<<(ostream& ut, KOMPLEX& k) { if (k.im < 0) ut << "(" << k.re << " - " << -k.im << "i)"; else ut << "(" << k.re << " + " << k.im << "i)"; return ut; } istream& operator>>(istream& in, KOMPLEX& k) { in >> k.re >> k.im; return in; } int main() { KOMPLEX a(1, 0), b(1, -2), c; c = a * b / (a + b); cout << a << endl; cin >> b >> c; cout << a << b << c << endl; } Körexempel ---------- (1 + 0i) 2.3 -4.9 8 100 (1 + 0i)(2.3 - 4.9i)(8 + 100i) 4. En enkel personklass ======================= *** En enkel personklass, utan några allokerade resurser. iostream> using namespace std; class Person { private: char namn[20 + 1]; int alder; public: Person(char* namn, int alder); friend ostream& operator<<(ostream& ut, Person& p); }; Person::Person(char* namn, int alder) { strcpy(this->namn, namn); this->alder = alder; } // Övning: Vad är fel här? ostream& operator<<(ostream& ut, Person& p) { cout << p.namn << ", " << p.alder << endl; return cout; } int main() { Person p1("Göran", 57); Person p2("Fredrik", 41); Person* pp = new Person("Gudrun", 58); cout << p1 << p2 << *pp; } Körexempel ---------- Göran, 57 Fredrik, 41 Gudrun, 58 5. Pekare till en egen resurs ============================= *** Personklass med en pekare till en egen resurs. *** Glöm inte att städa upp! person-2.cpp ------------ #include using namespace std; class Person { private: char* namn; int alder; public: Person(char* namn, int alder); friend ostream& operator<<(ostream& ut, Person& p); }; Person::Person(char* namn, int alder) { this->namn = new char[strlen(namn) + 1]; strcpy(this->namn, namn); this->alder = alder; } ostream& operator<<(ostream& ut, Person& p) { ut << p.namn << ", " << p.alder << endl; return ut; } int main() { char namn[20 + 1]; cout << "Ange namnet på en 57-årig politiker: " << endl; cin >> namn; Person p1(namn, 57); cout << "Ange namnet på en 41-årig politiker: " << endl; cin >> namn; Person p2(namn, 41); cout << p1 << p2; } Körexempel ---------- Ange namnet på en 57-årig politiker: Göran Ange namnet på en 41-årig politiker: Fredrik Göran, 57 Fredrik, 41 7. Destruktor ============= *** Personklass med en pekare till en egen resurs. *** Nu med en destruktor som avallokerar resursen. person-3.cpp ------------ #include using namespace std; class Person { private: char* namn; int alder; public: Person(char* namn, int alder); ~Person(); friend ostream& operator<<(ostream& ut, Person& p); }; Person::Person(char* namn, int alder) { this->namn = new char[strlen(namn) + 1]; strcpy(this->namn, namn); this->alder = alder; } Person::~Person() { delete[] namn; } ostream& operator<<(ostream& ut, Person& p) { cout << p.namn << ", " << p.alder << endl; return cout; } int main() { Person p1("Göran", 57); Person p2("Fredrik", 41); Person* pp = new Person("Gudrun", 58); cout << p1 << p2 << *pp; } Körexempel ---------- Göran, 57 Fredrik, 41 Gudrun, 58 7. Man kan skriva ut saker för att se vad som händer ==================================================== *** Samma personklass, med destruktor som avallokerar resursen. *** Nu med lite utskrifter vid skapande och uppstädning. person-4.cpp ------------ #include using namespace std; class Person { private: char* namn; int alder; int personnummer; static int antal_skapade_personer; public: Person(char* namn, int alder); ~Person(); friend ostream& operator<<(ostream& ut, Person& p); }; int Person::antal_skapade_personer = 0; Person::Person(char* namn, int alder) { this->namn = new char[strlen(namn) + 1]; strcpy(this->namn, namn); this->alder = alder; this->personnummer = ++antal_skapade_personer; cout << "Skapar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; } Person::~Person() { cout << "Rensar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; delete[] namn; } ostream& operator<<(ostream& ut, Person& p) { cout << "Person " << p.personnummer << ": " << p.namn << ", " << p.alder << endl; return cout; } int main() { Person p1("Göran", 57); Person p2("Fredrik", 41); Person* pp = new Person("Gudrun", 58); cout << p1 << p2 << *pp; } Körexempel ---------- Skapar person 1 (Göran, 57) med namnet på minnesadress 0x80490c9 Skapar person 2 (Fredrik, 41) med namnet på minnesadress 0x80490cf Skapar person 3 (Gudrun, 58) med namnet på minnesadress 0x80490d7 Person 1: Göran, 57 Person 2: Fredrik, 41 Person 3: Gudrun, 58 Rensar person 2 (Fredrik, 41) med namnet på minnesadress 0x804b018 Rensar person 1 (Göran, 57) med namnet på minnesadress 0x804b008 8. Copy-constructor, default-konstruktor, operator= =================================================== *** Personklassen, nu med tillägg: *** en copy-constructor, *** en konstruktor utan argument, *** tilldelningsoperator person-5.cpp ------------ #include using namespace std; class Person { private: char* namn; int alder; int personnummer; static int antal_skapade_personer; public: Person(char* namn, int alder); Person(const Person& p); Person(); ~Person(); const Person& operator=(const Person& p); friend ostream& operator<<(ostream& ut, Person& p); }; int Person::antal_skapade_personer = 0; Person::Person(char* namn, int alder) { this->namn = new char[strlen(namn) + 1]; strcpy(this->namn, namn); this->alder = alder; this->personnummer = ++antal_skapade_personer; cout << "Skapar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; } Person::Person(const Person& p) { this->namn = new char[strlen(p.namn) + 1]; strcpy(this->namn, p.namn); this->alder = p.alder; this->personnummer = ++antal_skapade_personer; cout << "Skapar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; } Person::Person() { this->namn = new char[2]; strcpy(this->namn, "X"); this->alder = -1; this->personnummer = ++antal_skapade_personer; cout << "Skapar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; } Person::~Person() { cout << "Rensar person " << personnummer << " (" << namn << ", " << alder << ") med namnet på minnesadress " << (void*)namn << endl; delete[] namn; } const Person& Person::operator=(const Person& p) { if (this != &p) { delete[] this->namn; this->namn = new char[strlen(p.namn) + 1]; strcpy(this->namn, p.namn); this->alder = p.alder; this->personnummer = p.personnummer; } return *this; } ostream& operator<<(ostream& ut, Person& p) { cout << "Person " << p.personnummer << ": " << p.namn << ", " << p.alder << endl; return cout; } int main() { Person p1("Göran", 57); Person p2("Fredrik", 41); Person p3 = p1; Person p4; p4 = p2; cout << p1 << p2 << p3 << p4; } Körexempel ---------- Skapar person 1 (Göran, 57) med namnet på minnesadress 0x8049527 Skapar person 2 (Fredrik, 41) med namnet på minnesadress 0x804952d Skapar person 3 (Göran, 57) med namnet på minnesadress 0x804b028 Skapar person 4 (X, -1) med namnet på minnesadress 0x804b038 Person 1: Göran, 57 Person 2: Fredrik, 41 Person 3: Göran, 57 Person 2: Fredrik, 41 Rensar person 2 (Fredrik, 41) med namnet på minnesadress 0x804b038 Rensar person 3 (Göran, 57) med namnet på minnesadress 0x804b028 Rensar person 2 (Fredrik, 41) med namnet på minnesadress 0x804b018 Rensar person 1 (Göran, 57) med namnet på minnesadress 0x804b008 9. Pekare till en extern resurs =============================== *** Personklass med en pekare till en extern resurs. *** Kan ge problem: Får INTE städas bort! person-6.cpp ------------ #include using namespace std; class Person { private: char* namn; int alder; public: Person(char* namn, int alder); friend ostream& operator<<(ostream& ut, Person& p); }; Person::Person(char* namn, int alder) { this->namn = namn; this->alder = alder; } ostream& operator<<(ostream& ut, Person& p) { ut << p.namn << ", " << p.alder << endl; return ut; } int main() { char namn[20 + 1]; cout << "Ange namnet på en 57-årig politiker: " << endl; cin >> namn; Person p1(namn, 57); cout << "Ange namnet på en 41-årig politiker: " << endl; cin >> namn; Person p2(namn, 41); cout << p1 << p2; } Körexempel ---------- Ange namnet på en 57-årig politiker: Göran Ange namnet på en 41-årig politiker: Fredrik Fredrik, 57 Fredrik, 41