Tässä koodailen olio-ohjelmoinnin harkkatyötä ja nyt olisi hakusessa parempi keino luokan tietojen käsittelyyn.
Class A: private: int maara; string nimi; double summa; public: A(); ~A(); int AnnaMaara(){return maara;} string AnnaNimi(){return nimi;} void AsetaNimi(string p_nimi){nimi = pnimi;}
Tuossa yllä esimerkkipätkä. Onko kellään antaa jotain fiksumpaa tapaa asettaa ja saada luokalta arvoja kuin tehdä oma metodi jokaiselle arvolla.
Omissa luokissa kun alkaa olla noita tietoja ihan hyvä määrä niin noita metodeja alkaa helposti syntyä melkoinen määrä. Ajattelin että pystyisikö tuohon tehdä jonkin yleisen Aseta() ja Anna() metodit joilla voisi käsitellä noita kaikkia luokan tietoja mutta itsellä ei ole käsitystä vielä miten moinen onnistuisi.
Polyformiset funktiot tuli ensimäisenä mieleen... Eli kaikille sama nimi, ja käytettävä funktio määräytyy parametri(e)n tyypin mukaan. Eka kerta kun autan ketään täällä, ja tämäkin oli vain hassu idea, joten kannattaa odottaa muiden mielipiteitä.
Ja näiden muuttujien on välttämättä oltava yksityisiä?
struct A { int a; }; A c; c.a = 5;
KoodiNoppa kirjoitti:
Polyformiset funktiot tuli ensimäisenä mieleen... Eli kaikille sama nimi, ja käytettävä funktio määräytyy parametri(e)n tyypin mukaan. Eka kerta kun autan ketään täällä, ja tämäkin oli vain hassu idea, joten kannattaa odottaa muiden mielipiteitä.
Mitenkäs tuollaisen toteuttaa käytännössä? Ja mitä jos luokalla on useita saman tyyppisiä arvoja?
Hmm... Ei kannata tästä lähtien kuunnella puheitani :(
Huomasin sen olevan ihan naurettava tapa ratkaista asia. Tuossakin on AnnaMaara ja AnnaNimi, joihin ei anneta parametriä, joten kone ei voi millään tietää palauttaakko int vai string... Pitäisi tehdä erinimiset funktiot ja palattaisiin alkutilanteeseen...
Ellei mikään sitä estä, käytä vinkkiä, jonka hejppa antoi.
EDIT: vielä niistä polymorfisista funktioista, vaikka niitä ei tässä tarvitsekaan:
http://www.nic.funet.fi/c opas/funktiot.html#polym
ellei niitä vielä ole opetettu (vai ymmärsinkö kysymykset väärin?)
Tietojen pitäisi olla yksityisiä. Pitää ilmeisesti vaan tehdä jokaiselle tiedolle omat metodit sitten.
Kurssi loppui noin vuosi sitten mutta harkkatyö on edelleen tekemättä. On tässä pikkuhiljaa aloittanut väkertämään tuota. Pitäisi syksyyn mennessä saada valmiiksi.
Yleensä noita samannimisiä funktioita yleensä kutsutaan ylikuormitetuiksi (overloaded).
Ei kai noille muutakaan voi kuin tehdä omat funktiot kaikille. Kuitenkin minusta asioita helpottaa, jos ne tekee tähän malliin:
private: int luku_m; public: int luku() {return luku_m;} void luku(int uusi_luku) {luku_m = uusi_luku;}
Viittausta käyttämällä saa kummatkin kärpäset samalla iskulla, mutta tällöin voisi minusta aivan hyvin käyttää julkista muuttujaa:
int& luku() {return luku_m;} // juttu.luku() = 10; cout << juttu.luku();
Jos ei millään jaksa tehdä noita kaikkia, voi vaikka tehdä makron, jolla luo muuttujan ja funktiot:
#define MAARITTELE(tyyppi, nimi) \ private: \ tyyppi nimi ## _m; \ public: \ const tyyppi& nimi() const {return nimi ## _m;} \ void nimi(tyyppi const& arvo) {nimi ## _m = arvo;} class palikka { MAARITTELE(int, a); // private: int a_m; public: int a() {...}; void a(int arvo) {...}; MAARITTELE(double, b); MAARITTELE(palikka*, toinen); };
Zmyrgel kirjoitti:
Tässä koodailen olio-ohjelmoinnin harkkatyötä ja nyt olisi hakusessa parempi keino luokan tietojen käsittelyyn. Onko kellään antaa jotain fiksumpaa tapaa asettaa ja saada luokalta arvoja kuin tehdä oma metodi jokaiselle arvolla.
Tuo on ihan riittävän fiksu tapa. Jos luokka käsittelee esim. päivämäärää, niin loogisimman metodit ovat mielestäni asetaPvm ja annaPvm -nimisiä. Tiedon piilotus ja kapselointi ovat ihan perusasioita olio-ohjelmoinnissa.
Zmyrgel kirjoitti:
Omissa luokissa kun alkaa olla noita tietoja ihan hyvä määrä niin noita metodeja alkaa helposti syntyä melkoinen määrä. Ajattelin että pystyisikö tuohon tehdä jonkin yleisen Aseta() ja Anna() metodit joilla voisi käsitellä noita kaikkia luokan tietoja mutta itsellä ei ole käsitystä vielä miten moinen onnistuisi.
Tuo on vielestäni turhaa kikkailua eikä valttämättä toimi ollenkaan. Esim. jos luokalla ovat kokonaislukuattribuutit a ja b, ja kokonaisluvun tallentava metodi Aseta(int), niin kumpaan attribuuttiin arvo tallennetaan?
Metabolix kirjoitti:
Viittausta käyttämällä saa kummatkin kärpäset samalla iskulla, mutta tällöin voisi minusta aivan hyvin käyttää julkista muuttujaa:
int& luku() {return luku_m;} // juttu.luku() = 10; cout << juttu.luku();
Tällaisella kikkailulla menetetään täysin kapseloinnin etu. Nyt, kun luvun tallentavaa metodia ei enää ole, ei voida enää hyödyntää kapselointia syötteen kelvollisuuden tarkistamiseen tms.
Yleensäkään luokan kaikkiin attribuutteihin ei tarvitse päästä käsiksi luokan ulkopuolelta. Varsinkin, jos haetaan perinteiselle kapseloinnille korvaajaa, on varmaankin parempi määritellä attribuutit julkisiksi tai käyttää muuta kuin luokkarakennetta (esim. struct).
A-P kirjoitti:
Tällaisella kikkailulla menetetään täysin kapseloinnin etu.
Tietenkin viittauksilla menetetään tuo mahdollinen etu, kun itse asiassa päädytään vain tekemään käytännössä julkinen muuttuja hieman hankalammin. Jos kuitenkin kyseessä on harjoitustehtävä, jossa opettaja on ohjeistanut vain tekemään muuttujista yksityisiä ja käyttämään käsittelyyn jäsenfunktioita, luultavasti itse tekisin sen noin ihan vain opettajaa kiusatakseni. "Oikeassa" ohjelmassa taas, jos arvolle ei tehdä tarkistusta tai mitään muuta ihmeellistä, käyttäisin ehdottomasti vain suoraan julkista muuttujaa.
Metabolix kirjoitti:
A-P kirjoitti:
Tällaisella kikkailulla menetetään täysin kapseloinnin etu.
Tietenkin viittauksilla menetetään tuo mahdollinen etu, kun itse asiassa päädytään vain tekemään käytännössä julkinen muuttuja hieman hankalammin. Jos kuitenkin kyseessä on harjoitustehtävä, jossa opettaja on ohjeistanut vain tekemään muuttujista yksityisiä ja käyttämään käsittelyyn jäsenfunktioita, luultavasti itse tekisin sen noin ihan vain opettajaa kiusatakseni.
Siinä harjoitustyössäkin on syytä opetella hyvää koodaustyyliä. Avainsana tässäkin tapauksessa on ylläpidettävyys. Kun nyt on olio-ohjelmoinnista kyse, kannattaa opetella paradigman mukana tuomat hyvät tavat/käytännöt. Maailma on jo valmiiksi täynnä huonosti ylläpidettävää koodia, joten mielestäni sitä on turha lisätä.
Alright, teen nyt kaikille omat metodit. On ainakin yksinkertaisin ratkaisu ja pääsee hommassa eteenpäin.
Moniperiyttäminen aiheuttaa tässä vielä hieman harmaita hiuksia mutta eiköhän sekin selviä kun lueskelee hieman tuota teoriaa taas ajatuksen kanssa.
Aiheen sivusta hieman mennen, tämä on hyvä esimerkki siitä miten esimerkiksi C# pelastaa päivän. Jos meillä on sinänsä julkisia muuttujia, on vähän turha tehdä metodikutsuja niiden asettamiseen ja lukemiseen. Eli voidaan määritellä suoraan:
public int Pituus;
Ylläpidettävyys kun on tärkeää, pitää silti miettiä josko joskus tuleekin jotain ehtoja. Luonnollisesti voidaankin haluta määritellä pituus aina positiiviseksi luvuksi (tietysti tämä hoituisi ihan unsigned-tyypin käytölläkin, mutta esimerkkinä kelvannee). Tämä kun tarvitaan, muutetaan vain palikan koodia:
private int _pituus; public int Pituus { get { return _pituus; } set { if (value < 0) throw new ArgumentException("Pituus ei voi olla pienempi kuin nolla!"); _pituus = value; } }
Ja hupsista, mitään muita palikoita ei tarvitse muuttaa kun molemmissa tavoissa homma toimii samalla tavalla:
ötökkä.Pituus = 10; Console.WriteLine(ötökkä.Pituus);
Niin, samoinhan tuo Delphissäkin, muistaakseni jotenkin näin:
_A: Integer; property A: Integer read _A write SetA; {Ja sitten toteutetaan se SetA}
Aihe on jo aika vanha, joten et voi enää vastata siihen.