Datorer och programmering TDB2: Aggregat Eva Pärt-Enander Aggregat i C++ Kan också kallas komposition. En klass eller objekt är uppbyggd av andra klasser eller objekt. En klass har attribut av andra, redan deklarerade, klasser. initieringslistor brukar användas i konstruktorerna. Antag att attributen i klassen klasssnamn heter d1, d2,... Då har vi: klassnamn::klassnamn( parameterlista ) : d1(uttryck1), d2(uttryck2),... \\ Ev. tilldelningar. 0-0 1 Exempel på konstruktorer Anmärkning (initieringslistor) Programkroppen måste vara med, även om den är tom. Oftast är initieringslista samma sak som att göra tilldelning, dvs klassnamn::klassnamn( parameterlista ) d1 = uttryck1; d2 = uttryck2;... etc I vissa fall måste man ha initieringslistor (attribut som är konstanter eller referenser t ex, eftersom dessa ej får tilldelas överkurs). initieringslistor kan ge eektivare kod när man initierar attribut som är objekt. Låt klassen daeck representera bildäck. const double MAXdjup = 20.00; // 2cm class daeck private: double djup; public: ; daeck(); daeck( double indjup ); double haemta_djup(); // Mönsterdjup, mm gummi int slitage( double slitdjup ); void skriv(); Då kan konstruktorerna se ut så här med tilldelning: daeck::daeck() djup = MAXdjup; daeck::daeck( double indjup ) djup = indjup; 2 3
eller så här med initieringslista: daeck::daeck() : djup(maxdjup) daeck::daeck( double indjup ) : djup(indjup) Implementation av metoder: //---Selektorer: double daeck::haemta_djup() return djup; //---Andra metoder: int daeck::slitage( double slitdjup ) // Slit ned ``slitdjup mycket av // gummit (om det går). // Returnera 1 om allt gummi slut, // annars 0. int slutgummi = 0; djup = 0; slutgummi = 1; else djup -= slitdjup; return slutgummi; void daeck::skriv() cout.setf( ios::fixed ); // snyggare utskrift cout << `` däck = `` << setprecision(1) << djup; if ( djup - slitdjup < 0 ) 4 5 Då kan konstruktorerna se ut så här: Låt oss nu skapa klassen bil som har fyra däck. Senare även: bensintank, x-position, framhjulsdriven,... class bil private: char namn[50]; daeck hf, vf, hb, vb; public: ; bil(); // biltyp // däcken bil( double nyhf, double nyvf, double nyhb, double nyvb ); bil( char nynamn[] ); void haemta_namn( char namnet[] ); void skriv(); void bromsa( double styrka );... etc. bil::bil() // Standardkonstruktorn för daeck // anropas automatiskt fyra ggr. strcpy(namn,"arne Anonym"); bil::bil( double nyhf, double nyvf, double nyhb, double nyvb ) : hf( daeck(nyhf) ), vf( daeck(nyvf) ), hb( daeck(nyhb) ), vb( daeck(nyvb) ) strcpy(namn,"arne Anonym"); bil::bil( char nynamn[] ) : hf( daeck(40.0) ), vf( daeck(40.0) ), hb( daeck(50.0) ), vb( daeck(50.0) ) strcpy(namn, nynamn); 6 7
Att jobba med aggregat Studera metoden bromsa i bil-klassen: void bromsa( double styrka ); Observera att om klass A innehåller objekt ur klass B, så anropas automatiskt klass B:s standardkonstruktor (default-konstruktor) om man ej anger ngt annat. där styrka anger hur hårt man bromsar, dvs hur mycket däcken slits. Enbart bakdäck. Implementationen skulle kunna se ut så här: void bil:: bromsa( double styrka ) const double broms = 0.5; int utangummi; Viktigt att alla klasser har standardkonstruktorer, annars får man kompileringsfel. // Slit på däcken och räkna hur // många som är utan gummi nu. gummi = vb.slitage( styrka*broms ) + hb.slitage( styrka*broms ); if ( utangummi >= 1 ) cout << ``Det luktar brännt gummi! 8 9 För att göra något med bilens däck, så måste man använda metoder i klassen daeck eftersom mönsterdjupet, djup, är private-deklarerad. Exempel på huvudprogram: int main() bil minbil( 20.0, 20.0, 30.0, 30.0 ); minbil.skriv(); minbil.bromsa( 3.0 ); // Bromsa hårt... minbil.skriv();... bil dinbil(``volvo); Jobbar ofta iterativt. Om man vid konstruktion av metod i klassen bil upptäcker att klassen daeck skulle behöva er metoder, då så skapar man dem och återvänder sedan till bil-klassen. Undvik kompilerings- och logiska fel: Jobba alltid lite i taget. Lägg till metod efter metod systematiskt inte allt på en gång!!!. Öka på med era attribut efter hand (bensintank, x-position,...). Testa efter hand! Ibland enklast att skriva main först, för att se vilka objekt och metoder man önskar ha. Sedan deklarerar man klasser och implementerar deras metoder. 10 11
Allt i livet är OO. Måste kunna hantera objekt på rätt sätt: Vi visar även bilens skriv-metod: void bil::skriv() // Får lite snyggare utskrifter... cout.setf( ios::fixed ); cout << ``Bilen av typen = `` << namn << ``\t har ``; // Skriver bara ut ena fram, ena bak hf.skriv(); hb.skriv(); dvs vi använder naturligtvis daeck-klassens skriv-metod T ex lokalt deklarerade objekt av samma/annan klass objekt av samma/annan klass som parameter returnera objekt av samma/annan klass returnera pekare till objekt i samma/annan klass använda metod i samma/annan klass använda konstruktorer på olika sätt använda selektorer lagom ofta. 12 13 Hantering array-attribut Enkelt att hitta exempel: alla problem som har många av samma sort, t ex: Simulera 2dim-bollhav. Antag bollarna far omkring slumpmässigt. Räkna antal som hamnar utanför! Kolla om bollar krockar. Lösning: Skapa klassen bollhav. Använd cirkel-klassen. Ha array av cirklar som attribut. Håll ordning på antal. Kassaapparat i en aär. Sälj varor, köp till lager, sätt jul-rea-priser på allt mm Lösning: Skapa klassen VaruLista. Använd Vara-klassen. Ha array av varor Håll ordning på antal. Simulera ett tåg där varje vagn har en specik vikt. Loket har en maximal dragvikt den orkar dra. Koppla på och av nya vagnar. Kolla loket orkar! Lösning: Skapa klassen Taag. Använd Vagn- och Lok-klasserna. Ha ett lok + array av vagnar Håll ordning på antal. 14 15
Aären på djupet - Vad göra med VaruLista-klassen? skapa varor läsa in data till varor (l/tangentbord) Förslag, frågor: beräkna totala lagervärdet Lagra alla varor i en statisk array Lista. sänka/höja priset på alla varor, givet procentpris Om man vill kan man, sedan då programet fungerar, göra om det till dynamisk array. skriva lagerrapport söka efter en speciell vara ta reda på antal varor i lager Ha ett attribut VaruAntal som anger aktuella antalet varor i arrayen Lista. Behöver vi er metoder i Vara-klassen? sortera alla varor i bokstavsordning... etc 16 17 Exempel på huvudprogram: VaruLista-klass nya metoder i Vara: Vid linjär sokning i arrayen Lista, bra att ha: int Vara:: MindreAen( Vara invara ); som kollar om Namn < invara.namn Om urvalssortering så bra att ha metoden #include <iostream.h> #include <string.h> #include "Vara.h" #include "VaruLista.h" //========================================== // Huvudprogram som testar klassen VaruLista // Filnamn: TestaVaruLista.cc //========================================== int main() VaruLista ICA; int Vara:: SammaVara( char invarunamn[] ); som kollar om Namn == invarunamn. Dessutom vanliga funktionen void Swap( Vara a, Vara b ); som byter värden på två varor. ICA.NyVara( Vara( "Ostkrokar", 1.00, 10 ) ); ICA.NyVara( Vara( "Ost", 2.00, 5 ) ); ICA.NyVara( Vara( "Mjölk", 5.00, 2 ) ); ICA.LaesIn(); cout << "\ntotala lagervärdet:" << ICA.LagerVaerde() cout << "\nnu är det Jul-REA i affären, " << "80 av ord. pris:" 18 19
ICA.ProcentPris( 0.80 ); cout << "\njul-reans totala lagervärde: " << ICA.LagerVaerde() << " SEK." ICA.SkrivLagerRapport( 1 ); cout << "\nge namnet på en speciell vara:" char Speciell[100]; cin.getline( Speciell, sizeof(speciell) ); cout <<" \nvaror med namnet " << Speciell << ":" ICA.Finn( Speciell ); ICA.Sortera(); cout << "Sorterat!!" ICA.SkrivLagerRapport( 1 ); Körningsexempel: Nytt varuantal 1 Nytt varuantal 2 Nytt varuantal 3 Nu finns 3 st olika varor. Hur många nya varor vill du lägga in? 2 Ge varans namn: Olja Ge pris och antal i lager: 14.00 100 Nytt varuantal 4 Ge varans namn: Korv Ge pris och antal i lager: 10.50 1 Nytt varuantal 5 Tack! Nu finns 5 st varor! Totala lagervärdet:1440.5 cout << "\neventuella varor som är slut: " ICA.SkrivLagerRapport( 0 ); return 0; Nu är det Jul-REA i affären, 80 av ord. pris: Jul-REANs totala lagervärde: 1152.4 SEK. 0 Varunamn: Sylt Pris: 0.8 Antal i lager: 10 20 21 Headerlen: 1 Varunamn: Ost Pris: 1.6 Antal i lager: 5 2 Varunamn: Mjöl Pris: 4 Antal i lager: 2 3 Varunamn: Olja Pris: 11.2 Antal i lager: 100 4 Varunamn: Korv Pris: 8.4 Antal i lager: 1 Ge namnet på en speciell vara: Olja Varor med namnet Olja: Varunamn: Olja Pris: 11.2 Antal i lage Sorterat!!! 0 Varunamn: Korv Pris: 8.4 Antal i lager: 1 1 Varunamn: Mjöl Pris: 4 Antal i lager: 2 2 Varunamn: Olja Pris: 11.2 Antal i lager: 100 3 Varunamn: Ost Pris: 1.6 Antal i lager: 5 4 Varunamn: Sylt Pris: 0.8 Antal i lager: 10 Eventuella varor som är slut: #ifndef VaruLista #define VaruLista // Klassdeklaration för klassen VaruLista. // Filnamn: VaruLista.h const int maxvara = 100; class VaruLista private: Vara Lista[maxvara]; int VaruAntal; public: VaruLista(); void NyVara( Vara V ); void LaesIn(); double LagerVaerde(); void Finn( char Vilken[] ); void ProcentPris( double Faktor ); void SkrivLagerRapport( int Alla ); void Sortera(); // void SparaPaaFil( char UtFilNamn[] ); // void LaesFraanFil( char InFilNamn[] ); ; #endif 22 23