Olio-ohjelmointi
Lisätehtäviä
Tehtävä 1: Creating a Class

Luo luokka Car, jolla on seuraavat yksityiset attribuutit: string make, string model ja int year. Kirjoita konstruktori, joka alustaa nämä attribuutit, ja metodi void display(), joka tulostaa auton tiedot.

Tehtävä 2: Encapsulation

Muokkaa Car-luokkaa edellisestä tehtävästä lisäämällä getter- ja setter-metodit jokaiselle attribuutille. Varmista, että asetettu data on validia (esim. vuoden tulee olla suurempi kuin 1885).

Tehtävä 3: Constructor Overloading

Lisää Car-luokkaan ylikuormitettu konstruktori, joka ottaa parametreina vain make ja model. Tässä tapauksessa year saa oletusarvon 2020. Käytä tätä ylikuormitettua konstruktoria olioiden luomiseen.

Tehtävä 4: Inheritance

Luo luokka ElectricCar, joka perii Car-luokan. Lisää yksityinen attribuutti int batteryCapacity ja metodi void charge(), joka tulostaa viestin, että auto latautuu.

Tehtävä 5: Polymorphism

Ylikirjoita ElectricCar-luokassa display()-metodi niin, että se sisältää myös akun kapasiteetin tiedot. Luo Car-olioista koostuva vektori, joka sisältää sekä Car- että ElectricCar-olioita. Käytä polymorfismia kutsuaksesi display()-metodia jokaiselle oliolle.

OHJE: Polymorfismi vaatii osoittimia tai viittauksia! Käytä unique_ptr:ää:

vector<unique_ptr<Car>> carList;

carList.push_back(make_unique<Car>());
carList.push_back(make_unique<ElectricCar>());

for (const auto& obj : carList) {
    obj->display();  // Kutsuu oikean luokan display():ta (polymorfismi)
}
Miksi ei vector<Car>? Jos tallennat olioita suoraan (ei osoittimia), tapahtuu object slicing:
  • ElectricCar-olio "leikataan" → vain Car-osa jää jäljelle
  • Akun kapasiteetti ja kaikki ElectricCar:n lisätiedot katoavat
  • Polymorfismi ei toimi!
Huom: auto antaa kääntäjän päätellä tyypin automaattisesti. Tässä obj on tyyppiä const unique_ptr<Car>&.

Tehtävä 6: Virtual Functions

Tee Car-luokan display()-metodista virtuaalinen (virtual), ja havainnollista miten virtuaaliset funktiot mahdollistavat ajoaikaisen polymorfismin.

Tapa 1: Käytä unique_ptr:ää kantaluokan osoittimena, joka osoittaa johdettuun olioon:

unique_ptr<Car> objectCar = make_unique<ElectricCar>();
objectCar->display();  // Kutsuu ElectricCar::display() jos virtual

Tapa 2: Jos haluat käyttää pinomuistissa olevia olioita, voit käyttää viitettä:

ElectricCar objectElectricCar;
Car& carRef = objectElectricCar;
carRef.display();  // Kutsuu ElectricCar::display() jos virtual

Tehtävä: Testaa molempia tapoja ja katso, mikä ero on kun display() on virtual vs. ei-virtual.

Tehtävä 7: Abstract Class

Luo abstrakti luokka Vehicle, jolla on puhdas virtuaalifunktio void start() = 0. Peri tästä luokasta Car- ja Motorcycle-luokat. Toteuta start()-metodi molemmissa johdetuissa luokissa.

Testaa polymorfismia: Luo vector<unique_ptr<Vehicle>> ja lisää siihen sekä Car- että Motorcycle-olioita. Käy läpi vektori ja kutsu start() jokaiselle ajoneuvololle.

Muistutus: Abstraktista luokasta ei voi luoda olioita suoraan - vain perivistä luokista!

Tehtävä 8: Multiple Inheritance

Luo luokka HybridCar, joka perii sekä Car-luokan että toisen luokan nimeltä FuelCar. Lisää FuelCar-luokkaan attribuutti int fuelTankCapacity ja havainnollista, miten moniperintä toimii C++:ssa.

Tehtävä 9: Destructor

Toteuta Car-luokkaan destruktori, joka tulostaa viestin (esim. auton mallin), kun Car-olio tuhotaan. Havainnollista destruktorien kutsumista:

  • Pinomuistissa: Luo Car-olio sisemmässä scope:ssa { Car obj; } ja katso milloin destruktori kutsutaan.
  • Dynaamisessa muistissa: Luo unique_ptr<Car> ja katso milloin destruktori kutsutaan kun unique_ptr poistuu scopesta.
  • Vektorissa: Luo vector<unique_ptr<Car>>, lisää autoja ja katso milloin ne tuhoutuvat.

Huom: Lisää myös konstruktoriin cout-tulostus, jotta näet luomis- ja tuhoutumisjärjestyksen!

Tehtävä 10: Kompositio vektorilla

Luo kaksi luokkaa: Book ja Library. Book-luokalla tulee olla:

  • string-attribuutit: title ja author.
  • Konstruktori näiden attribuuttien alustamiseen.
  • Metodi display(), joka tulostaa kirjan tiedot.

Library-luokan tulee:

  • Sisältää vector<unique_ptr<Book>> kirjojen tallentamiseen (kompositio).
  • Sisältää konstruktorin, joka alustaa kirjaston nimen.
  • Sisältää metodin addBook(string title, string author), joka luo uuden kirjan ja lisää sen vektoriin.
  • Sisältää metodin displayBooks(), joka tulostaa kaikki kirjat.
  • Destruktorin ei tarvitse vapauttaa muistia - unique_ptr hoitaa sen automaattisesti!

Tehtävä: Toteuta molemmat luokat ja testaa ne luomalla Library-olio, lisäämällä kirjoja ja tulostamalla ne.

Vihje: Käytä push_back(make_unique<Book>(...)) kirjojen lisäämiseen vektoriin.

Tehtävä 11: Kompositio (Laptop)

Luo kolme luokkaa: Screen, Keyboard ja Laptop.

Screen-luokalla tulee olla:

  • float-attribuutti size (tuumina).
  • Konstruktori ja metodi display(), joka tulostaa näytön koon.

Keyboard-luokalla tulee olla:

  • string-attribuutti layout (esim. "QWERTY").
  • Konstruktori ja metodi display(), joka tulostaa näppäimistön asettelun.

Laptop-luokalla tulee olla:

  • unique_ptr<Screen> jäsenenä (kompositio - laptop omistaa näytön).
  • unique_ptr<Keyboard> jäsenenä (kompositio - laptop omistaa näppäimistön).
  • Konstruktori, joka luo Screen- ja Keyboard-oliot make_unique:lla.
  • Metodi display(), joka tulostaa näytön ja näppäimistön tiedot.

Tehtävä: Toteuta luokat ja testaa ne luomalla Laptop-olio ja kutsumalla sen display()-metodia.

Huom: Tämä on kompositio, koska Laptop omistaa näytön ja näppäimistön. Kun laptop tuhoutuu, myös näyttö ja näppäimistö tuhoutuvat automaattisesti.

Tehtävä 12: Sisäkkäinen kompositio (Nested Composition)

Luo kolme luokkaa: Address, Person ja Company.

Address-luokalla tulee olla:

  • string-attribuutit: street ja city.
  • Konstruktori attribuuttien alustamiseen.
  • Metodi display() osoitteen tulostamiseen.

Person-luokalla tulee olla:

  • string-attribuutti name.
  • unique_ptr<Address> jäsenenä (kompositio - henkilö omistaa osoitteen).
  • Konstruktori, joka luo Address-olion make_unique:lla.
  • Metodi display(), joka tulostaa henkilön nimen ja osoitteen.

Company-luokalla tulee olla:

  • string-attribuutti companyName.
  • unique_ptr<Person> jäsenenä (kompositio - yritys omistaa toimitusjohtajan).
  • Konstruktori, joka luo Person-olion make_unique:lla.
  • Metodi display(), joka tulostaa yrityksen nimen ja toimitusjohtajan tiedot.

Tehtävä: Toteuta luokat ja testaa ne luomalla Company-olio ja kutsumalla sen display()-metodia.

Sisäkkäinen kompositio (Nested Composition) tarkoittaa:

  • Company omistaa Person-olion (kompositio)
  • Person omistaa Address-olion (kompositio)
  • Kun Company tuhoutuu → Person tuhoutuu → Address tuhoutuu (ketjureaktio!)

Lisää destruktoreihin cout-tulosteet, jotta näet tuhoutumisjärjestyksen!

Tehtävä 13: Exception Handling

Luo Car-luokkaan metodi void drive(int distance), joka heittää poikkeuksen, jos distance on negatiivinen. Käytä try- ja catch-lohkoja tämän poikkeuksen käsittelemiseksi pääfunktiossa.

Tehtävä 14: Friend Functions

Huom! Friend-funktio ei kuulu kurssin sisältöön. Tässä lyhyesti siitä:

  • Friend-funktio on erikoisfunktio, jolla on pääsy luokan yksityisiin (private) ja suojattuihin (protected) jäseniin, vaikka se ei ole luokan jäsenfunktio.
  • Friend-funktio määritellään friend-avainsanalla luokan sisällä, mutta sitä ei määritellä luokan jäsenfunktioksi.
  • Friend-funktio toteutetaan normaalina funktiona luokan ulkopuolella.
Lisätietoa: tutorialspoint.com - cpp_friend_functions

Kirjoita friend-funktio compareCars(), joka vertaa kahden Car-olion year-attribuuttia ja palauttaa uudemman auton. Havainnollista friend-funktion käyttö pääfunktiossa.



Toggle Menu