Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Luokan tietojen käsittely

Sivun loppuun

Zmyrgel [03.06.2007 16:35:38]

#

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.

KoodiNoppa [03.06.2007 16:59:25]

#

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ä.

hejppa [03.06.2007 17:02:22]

#

Ja näiden muuttujien on välttämättä oltava yksityisiä?

struct A { int a; };
A c;
c.a = 5;

Zmyrgel [03.06.2007 17:12:51]

#

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?

KoodiNoppa [03.06.2007 17:29:37]

#

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?)

Zmyrgel [03.06.2007 18:07:56]

#

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.

Metabolix [04.06.2007 08:31:06]

#

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);
};

A-P [04.06.2007 10:58:21]

#

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).

Metabolix [04.06.2007 21:49:05]

#

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.

A-P [04.06.2007 23:05:46]

#

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ä.

Zmyrgel [05.06.2007 11:27:17]

#

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.

feenix [05.06.2007 14:42:46]

#

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);

Metabolix [05.06.2007 20:56:19]

#

Niin, samoinhan tuo Delphissäkin, muistaakseni jotenkin näin:

_A: Integer;
property A: Integer read _A write SetA; {Ja sitten toteutetaan se SetA}

Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta