Föreläsningsanteckningar OOP-föreläsning 9, måndag 8 oktober 2007 ================================================================= Idag ==== 1. Information om information i morgon om SDU2-kursval 2. Hemläxan om bilpekarna 3. Geometriska figurer, enkelt och fel 4. Geometriska figurer, med virtuella funktioner 5. Kan ni hitta felet? Och vad händer? 6. Ett problem inom objektorientering 7. Geometriska figurer med C++/CLI i Visual Studio 2005 8. Multipelt arv 9. Ofta är aggregat ("består av") bättre än multipelt arv 2. Hemläxan om bilpekarna ========================= http://www.aass.oru.se/~tpy/oop/2007-2008-p1/forelasningar-2007/bilpekarna/index.html 3. Geometriska figurer, enkelt och fel ====================================== figurer-1.cpp ------------- #include #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 << "En rektangel med bredden " << bredd << " och höjden " << hojd << endl; } //---------------------------------------------------------- class CIRKEL : public FIGUR { private: double radie; static const double PI = 3.1415926535; // Funkar i Gcc. Hur är det i VS? 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 << "En cirkel med radien " << 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 << "En kvadrat med sidan " << 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 En rektangel med bredden 10 och höjden 17.3 r1:s area = 173 Namn: c1 En cirkel med radien 10 c1:s area = 314.159 Namn: k1 En kvadrat med sidan 10 k1:s area = 100 Namn: k2 En kvadrat med sidan 12.5 k2:s area = 156.25 Namn: k3 4. Geometriska figurer, med virtuella funktioner ================================================ figurer-2.cpp ------------- #include #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; 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 << "En rektangel med bredden " << bredd << " och höjden " << hojd << endl; } //---------------------------------------------------------- class CIRKEL : public FIGUR { private: double radie; static const double PI; public: CIRKEL(string namn, double radie); void skriv(); double area(); }; const double CIRKEL::PI = 3.1415926535; CIRKEL::CIRKEL(string namn, double radie) : FIGUR(namn) { this->radie = radie; } double CIRKEL::area() { return PI * radie * radie; } void CIRKEL::skriv() { FIGUR::skriv(); cout << "En cirkel med radien " << 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 << "En kvadrat med sidan " << 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 En rektangel med bredden 10 och höjden 17.3 r1:s area = 173 Namn: c1 En cirkel med radien 10 c1:s area = 314.159 Namn: k1 En kvadrat med sidan 10 k1:s area = 100 Namn: k2 En kvadrat med sidan 12.5 k2:s area = 156.25 Namn: k3 En kvadrat med sidan 12.5 k3:s area = 156.25 Sammanlagda arean = 899.659 5. 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 6. Ett problem inom objektorienterad design =========================================== Är en kvadrat verkligen en rektangel? (Även känt som: Är en cirkel verkligen en ellips?) 7. Geometriska figurer med C++/CLI i Visual Studio 2005 ======================================================= (Man kan skapa konsolprojekt även för .NET) CLI_konsol_text.cpp ------------------- #include "stdafx.h" #include using namespace System; //---------------------------------------------------------- ref class FIGUR abstract { private: System::String^ namn; FIGUR^ next; static FIGUR^ first = nullptr; public: FIGUR(System::String^ namn); virtual void skriv(); virtual double area() = 0; static double total_area(); }; FIGUR::FIGUR(System::String^ namn) { this->namn = namn; next = first; first = this; } void FIGUR::skriv() { Console::WriteLine(L"Namn: " + namn); } double FIGUR::total_area() { FIGUR^ p = first; double summa = 0; while (p != nullptr) { summa += p->area(); p = p->next; } return summa; } //---------------------------------------------------------- ref class REKTANGEL : public FIGUR { private: double bredd, hojd; public: REKTANGEL(System::String^ namn, double bredd, double hojd); virtual void skriv() override; virtual double area() override; }; REKTANGEL::REKTANGEL(System::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(); Console::WriteLine(L"Bredd: " + bredd + L", höjd: " + hojd); } //---------------------------------------------------------- ref class CIRKEL : public FIGUR { private: double radie; static const double PI = 3.1415926535; public: CIRKEL(System::String^ namn, double radie); virtual void skriv() override; virtual double area() override; }; CIRKEL::CIRKEL(System::String^ namn, double radie) : FIGUR(namn) { this->radie = radie; } double CIRKEL::area() { return PI * radie * radie; } void CIRKEL::skriv() { FIGUR::skriv(); Console::WriteLine(L"Radie: " + radie); } //---------------------------------------------------------- ref class KVADRAT : public REKTANGEL { public: KVADRAT(System::String^ namn, double sida); virtual void skriv() override; }; KVADRAT::KVADRAT(System::String^ namn, double sida) : REKTANGEL(namn, sida, sida) { } void KVADRAT::skriv() { FIGUR::skriv(); Console::WriteLine(L"Sida: " + sqrt(area())); // sqrt, eftersom sidomåtten är privata i REKTANGEL } //---------------------------------------------------------- int main(array ^args) { // FIGUR f1(L"f1"); -- Går inte, för FIGUR är en abstrakt klass REKTANGEL r1(L"r1", 10, 17.3); r1.skriv(); Console::WriteLine(L"r1:s area = " + r1.area()); CIRKEL c1(L"c1", 10); c1.skriv(); Console::WriteLine(L"c1:s area = " + c1.area()); KVADRAT k1(L"k1", 10); k1.skriv(); Console::WriteLine(L"k1:s area = " + k1.area()); KVADRAT^ k2p = gcnew KVADRAT(L"k2", 12.5); k2p->skriv(); Console::WriteLine(L"k2:s area = " + k2p->area()); FIGUR^ k3p = gcnew KVADRAT(L"k3", 12.5); k3p->skriv(); Console::WriteLine(L"k3:s area = " + k3p->area()); Console::WriteLine(L"Sammanlagda arean = " + FIGUR::total_area()); } Körexempel ---------- Namn: r1 Bredd: 10, höjd: 17,3 r1:s area = 173 Namn: c1 Radie: 10 c1:s area = 314,15926535 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 Sammanlagda arean = 899,65926535 Press any key to continue . . . 8. Multipelt arv ================ Ur platta-1.cpp --------------- class ELAPPARAT { private: int me; // Märkeffekt double pos; // KNapposition 0.0-1.0 public: ELAPPARAT(int me, double pos); double effekt(); }; ELAPPARAT::ELAPPARAT(int me, double pos) { this->me = me; this->pos = pos; } double ELAPPARAT::effekt() { return me*pos; } //---------------------------------------------------------- class PLATTA : public ELAPPARAT, public CIRKEL { public: PLATTA(int me, double pos, string namn, double radie); double area_effekt(); }; PLATTA::PLATTA(int me, double pos, string namn, double radie) : ELAPPARAT(me, pos), CIRKEL(namn, radie) { } double PLATTA::area_effekt() { return effekt() / area(); } //---------------------------------------------------------- int main() { PLATTA p1(1500, 0.5, "p1", 0.15); cout << "Plattans area: " << p1.area() << endl; cout << "Plattans areaeffekt: " << p1.area_effekt() << " W/m2" << endl; } 9. Ofta är aggregat ("består av") bättre än multipelt arv ========================================================= Ur platta-2.cpp --------------- class PLATTA { private: ELAPPARAT ea; CIRKEL c; public: PLATTA(int me, double pos, string namn, double radie); double area_effekt(); double area(); }; PLATTA::PLATTA(int me, double pos, string namn, double radie) : ea(me, pos), c(namn, radie) { } double PLATTA::area_effekt() { return ea.effekt() / c.area(); } double PLATTA::area() { return c.area(); } //---------------------------------------------------------- int main() { PLATTA p1(1500, 0.5, "p1", 0.15); cout << "Plattans area: " << p1.area() << endl; cout << "Plattans areaeffekt: " << p1.area_effekt() << " W/m2" << endl; }