[alla radantal som nämns är exklusive kommentarer, tomrader och rader med enbart klammerparentes] Uppgift 1 ========= Givet i uppgiften och given kod är att två klasser behövs, Map och "island", samt att dessa ska vara filuppdelade. I uppgiften framgår vilka datamedlemmar som behövs i kartan och i givna koden framgår hur en karta skapas vilket ger hur konstruktorn behöver vara skapt. Tänk till extra om hur "ett antal öar" representeras. Vi föreslår en vector med öar. Vi ser i givna koden även anrop till add_island(). Det mest logiska är att den funktionen tar emot *en* ö vilket ger att en ö måste ha en konstruktor kompatibel med konstruktionen {1,9} vilket ger hur ö-konstruktorn måste vara skapt. Datamedlemmar ges i uppgiften. Tänk till extra om hur kustlinjen "alltid tecknet O" representeras. Därmed är grunden för båda klasserna lagd. Återstår att fördela kraven i uppgiftens punktlista till rätt klass med rätt skydd. * lägga till öar på kartan * kontrollera om ö på [kartas] x,y * skriva ut [kartas] x,y på ström (hjälpfunktion till nedan) * skriva ut karta på ström (given kod för detta) och operator för detta * operator+ för kartor Vi ser snabbt att samtliga funktioner opererar på kartor och därför bör vara medlemsfunktioner i den klassen. Kartutskriftoperatorn delas med fördel upp i tre funktioner: hjälpfunktionen, en medlemsfunktion för utskrift av hela kartan (given kod för detta som även indikerar var hjälpfunktionen bör anropas, och operator<< som kan använda medlemsfunktionen för kartutskrift. De funktioner som är användbara för den som skapat en karta blir publika. Undantaget är hjälpfunktionen som lämpligen läggs privat. Fundera igenom parametrar och returvärden, de bör falla sig naturligt i de fall de inte är givna av omständigheterna. Tänk till om reglerna för hur const ska användas. Tänk till om reglerna för "using namespace" i h-fil. Återstår att implementera allt. Först görs h-filer med alla deklarationer och header-guard. Sedan cc-filer med alla funktionsdefinitioner. För operatorerna gäller att tänka till särskilt hur de placeras. Kan resp. operator vara medlem eller ej? Hur gör en fri (ej medlem) operator för att lösa sin uppgift utan att kunna komma åt privata medlemmar och utan att använda förbjudna "friend"? add_island: tillägg i ö-behållare, 1 rad have_island_at: iterera ö-behållare och kontrollera om någon ö matcher koordinaterna, 5 rader print_content_at: om have_island_at ger att koordinaten är en ö, skriv O annars mellanrum, 4 rader print: använd given kod och ändra kommentaren till rätt anrop, 8 rader operator<<: anropa print, 1 rad operator+: skapa ny karta med lämplig storlek, kopiera över alla öar, 6 rader Kompilera. Tänk till om lämpliga varningsflaggor. Tänk till om vilka filer som ska och inte ska stå med i kompileringskommandot. Fixa alla varningar och fel och testkör tills allt fungerar. Klar! Uppgift 2 ========= Filuppdelning nämns varken som krav eller som att du slipper. Fråga om det eftersom det hör till god konvention att göra och god konvention är ett krav. I detta fall slipper vi filuppdelning, så dumpa all kod i en kopia av den givna filen. Skriv deklarationer för punktlistan i uppgiften en punkt i taget. Du behöver känna till "basklass", "arv" och hur "get_styled" ska kunna göra olika saker beroende på klass ("virtual", "override"). Konstruktor deduceras från givet testprogram. Tänk till om var "const" ska användas. Varje klass behöver en konstruktor som är korrekt, dvs anropar basklassens konstruktor före initiering av egna medlemmar. I vissa fall kan "using" användas för att minska skrivandet. Lägg till funktionsdefinitioner för "get_styled" i respektive klass enligt uppgiften. Du behöver komma på ett sätt att skapa en strängkopia med mellanrum mellan varje bokstav. En rättfram metod är att för varje tecken i originalet lägga till både tecknet och ett mellanrum. För att inte få ett mellanrum först eller sist är ett behändigt trick att hantera antingen första eller sista tecknet utanför loopen. Respektive "get_styled" behöver åtkomst av originalsträngen som naturligtvis inte får vara public. Gör antingen publik åtkomstfunktion eller använd "protected". Lägg till en loop för att ta bort alla dynamiskt allokerade objekt i huvudprogrammet. Tänk på vilka destruktorer som anropas och vilka som inte anropas beroende på hur du använt "virtual". Kompilera. Tänk till om lämpliga varningsflaggor. Tänk till om vilka filer som ska och inte ska stå med i kompileringskommandot. Fixa alla varningar och fel och testkör tills allt fungerar. Klar! Uppgift 3 ========= Titta på den givna koden. Medlemsfunktionerna ser intakta ut, men det saknas klassdefinition, public/private, datamedlemmar, konstruktor och alla speciella medlemsfunktioner. Ett konstruktoranrop ges av testfall 1 i huvudprogrammet. Från medlemsfunktionen push ser vi att "head" måste vara en datamedlem av typ "Node*", om vi inte minns detta från List-labben. Lämpligt startvärde är "nullptr". Externt användbara medlemsfunktioner blir publika, hjälpfunktioner, interna datatyper och medlemmar blir privata. Uppgiften kräver de fem speciella medlemsfunktionerna. Gör en i taget. Destruktor, 2 rader: Alt 1: Anropa pop tills stacken är tom. Alt 2: Ta bort head noden tills head är nullptr. Nästa head behöver sparas temporärt innan borttagning av head. Alt 3: Gör en rekursiv hjälpfunktion som hittar sista noden och på rekursionens återväg tar bort varje nod från slutet. delete_tail(Node* n): if n == nullptr: return; else: delete_tail(n->next); delete n; Alt 4: Gör en nod-destruktor så delete head automatisk triggar delete next. Funktionen pop behöver justeras så den inte avallokerar allt. Kopieringskonstruktor, hjälpfunktion 4 rader: Originalet ska kopieras till en helt ny (oinitierad) stack. Inför en hjälpfunktion clone som kopiera hela stacken rekursivt. Node* clone(Node* n): if n == nullptr: return nullptr; else: return new Node(n->value, clone(n->next)); Använd clone för att initiera nya stacken. Flyttkonstruktor, 1 rad: Originalet behöver inte bevaras, djup kopiering ska undvikas, originalet kan flyttas till nya stacken. Initiera nya stacken med originalets head. Sätt originalets head till nullptr. Kopieringstilldelning (operator=), 3 rader: Originalet ska skriva över en befintlig stack. Använd idiomet kopiera och byt. Glöm inte datamedlemmar utöver head, om några. returnera referens till överskrivna stacken (*this) Flyttilldelning (operator=), 2 rader: Originalet behöver inte bevaras, djup kopiering ska undvikas, originalet kan flyttas till nya befintlig stack. Befintlig stack måste tas om hand rätt. Byt helt enkelt plats på original och befintlig stack (head). Originalet kan tömmas och sättas till nullptr direkt, men det behövs inte eftersom det ändå händer när destruktorn anropas (så småningom). Implementera samtliga efterfrågade testfall och se till de fungerar. Kontrollera med valgrind att inga minnesläckor uppstått. TEST_CASE("all") { // 1 Stack A{}; A.push(2); A.push(5); A.push(8); CHECK( ! A.empty() ); CHECK( A.top() == 8 ); // 2 Stack B{A}; CHECK( ! B.empty() ); CHECK( B.top() == 8 ); // 3 B.pop(); B.pop(); CHECK( ! B.empty() ); CHECK( B.top() == 2 ); // 4 B.push(4); CHECK( ! B.empty() ); CHECK( B.top() == 4 ); // 5 A.pop(); CHECK( ! A.empty() ); CHECK( A.top() == 5 ); // 6 A.pop(); A.pop(); CHECK( A.empty() ); // 7 A = std::move(B); CHECK( B.empty() ); CHECK( ! A.empty() ); CHECK( A.top() == 4 ); // 8 Stack C{std::move(A)}; CHECK( A.empty() ); CHECK( ! C.empty() ); CHECK( C.top() == 4 ); // 9 Stack D; D.push(3); CHECK( ! D.empty() ); CHECK( D.top() == 3 ); // 10 C = D; CHECK( ! C.empty() ); CHECK( C.top() == 3 ); // 11 C.pop(); CHECK( C.empty() ); CHECK( ! D.empty() ); CHECK( D.top() == 3 ); // 12 D.push(1); D.push(2); D.push(6); D.push(7); } Uppgift 4 ========= Du vill ha en 5:a, rätt? Om du nöjer dig med en 4 löser du uppgift 3 snabbare då den mest kräver "standard boilerplate code". Vi ska skapa två klasser. Det är bara att läsa uppgiften och given kod noga flera gånger och sätta igång. Eko_Index: * Konstruktor som tar in std::initializer_list och kopierar till datamedlem (vector) * Medlemsfunktion "is_eko_word" för att ta reda på om ett ord finns i indexet (vectorn) * Medlemsfunktion "get_eko_value" som fungerar enligt beskrivning, använd strängström för att enklast iterera alla ord i inparametern * Kopieringskonstruktor och tilldelningsoperator borttagna för att hindra kopiering av index-objekt. Forest_Report: Har skogens namn, en lista med trädbeskrivningar och ett Eko_Index. Eftersom Eko_Index inte får kopieras måste det lagras som en referens i klassen. Hur en trädbeskrivning ser ut ges av anropen till "add_tree_values" i huvudprogrammet (flerordssträngar). I övrigt rättfram imlementation: * Konstruktorn måste speciellt (som alltid) använda datamedlemsinitieringslista, annars kan inte referenser eller konstanter i klassen initieras. * add_tree_values lägger till en trädbeskrivning, bara pusha till vector * Summera eko_värdet för alla trädbeskrivningar (varje index i vectorn), använder naturligtvis redan gjorda "get_eko_value" * Getter för skogens namn Kontrollera alla krav i uppgiften igen. Kompilera. Tänk till om lämpliga varningsflaggor. Tänk till om vilka filer som ska och inte ska stå med i kompileringskommandot. Fixa alla varningar och fel och testkör tills allt fungerar. Klar!