Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointiongelmat: C++ Olioiden välisiä toimintoja

Sivu 1 / 1

Sivun loppuun

Himmeli666 [03.10.2019 19:28:15]

Lainaa #

Tässä C++ perusteita treenataan ja tehtävänantona on saada tulosteeksi tämä:
Syötä ensimmäinen kokonaisluku:33
Syötä toinen kokonaisluku:22
Lukujen summa: 55

Koodini ei tulosta summaa ja eri variaatioilla olen nyt testannut miten saisin summan tulostetuksi, mutta ei vain onnistu. Nyt kaipaisin osaavempien apua.

#include <iostream>
using namespace std;

class Laskin
{
  public:
  int Summa(int eka, int toka);
};

int Laskin::Summa(int eka, int toka)
{
  int summa = eka + toka;
  return summa;
}
class Tulostaja : public Laskin
{
	public:
	int eka, toka;
	void Tulosta();
};
	void Tulostaja::Tulosta()
{
     	cout << "Syötä ensimmäinen kokonaisluku:" ;
	 	cin >> eka;
	 	cout << "Syötä toinen kokonaisluku:" ;
	 	cin >> toka;
}
void Tulostaja::Tulosta(int Summa)
{
		cout << "Lukujen summa:" <<<< Summa << endl;
}
return Tulostaja;}

int main()
{
  Tulostaja olio;
  olio.Tulosta();
}

Teuro [03.10.2019 20:18:29]

Lainaa #

komentorivi kirjoitti:

g++ tulostaja.cpp -c
tulostaja.cpp:28:6: error: no declaration matches 'void Tulostaja::Tulosta(int)'

void Tulostaja::Tulosta(int Summa)
^~~~~~~~~
tulostaja.cpp:21:7: note: candidate is: 'void Tulostaja::Tulosta()'
void Tulostaja::Tulosta()
^~~~~~~~~
tulostaja.cpp:15:7: note: 'class Tulostaja' defined here
class Tulostaja : public Laskin
^~~~~~~~~
tulostaja.cpp:32:1: error: expected unqualified-id before 'return'
return Tulostaja;}
^~~~~~
tulostaja.cpp:32:18: error: expected declaration before '}' token
return Tulostaja;}
^

Vaikuttaa toisaalta koulutehtävältä, joihin ei anneta valmista ratkaisua. Toisaalta vaikuttaa ettei kyseessä ole kovinkaan laadukas koulutus. Onko tuo olio-himmeli tullut koulun puolelta vaatimuksena vai oletko päätynyt itse tuollaiseen rakenteeseen? Tässä olioista ei ole mitään etua ne vain sotkevat asiaa. Eli jos voit, niin tee ohjelma ilman olioita, jolloin ohjelmasta tulee selkeästi lyhyempi ja saat sen toimimaan paljon varmemmin.

Himmeli666 [03.10.2019 21:05:59]

Lainaa #

Koodista oli valmiiksi annettu alku ja loppu. Minun tehtäväksi jäi täydentää tulostaja olio siten, että koodi tulostaa yllä mainitun tulosteen. Kurssi on verkkokurssi ja kyllä, mielestäni aineisto on melko suppea ja en tahdo löytää ratkaisua miten saisin tuon summan tuolta tulostumaan.

Teuro [03.10.2019 21:25:39]

Lainaa #

Tulostaja-olio pitäisi kaiketi tulostaa laskimen laskema summa. Tulostajan ei tule varmaankaan periytyä laskinluokasta, eikä ainakaan pyytää käyttäjän syötettä. Syötteen lukeminen, tulosten manipulointi ja tulosten tulostaminen pitäisi olla selkeästi erillään toisistaan.

Voitko liittää vielä valmiina annetun koodin, johon muutokset pitäisi tehdä?

vesikuusi [03.10.2019 21:29:42]

Lainaa #

Minusta on aina ollut surullista miten monessa paikkaa tuntuu olevan tällaisia ongelmia etenkin olio-ohjelmoinnin opetuksessa. Ei tuollaisen sotkun opettamisesta voi olla mitään hyötyä. Itsellänikin meni pitkään että sain oikaistua väärinymmärrykseni, kiitos kirjojen ja artikkelien joissa opetettiin tekemään tyyliin

class Dog : public Animal { void say() { std::cout << "vuh!" << std::endl; } };

. (Mistä helvetistä nämä eläinesimerkitkin on alunperin revitty?)

Himmeli666 kirjoitti:

Koodini ei tulosta summaa ja eri variaatioilla olen nyt testannut miten saisin summan tulostetuksi, mutta ei vain onnistu.

Mitä ohjelmasi nyt tekee? Mitä olisit odottanut sen tekevän? Nämä ovat tärkeämpiä seikkoja kuin se, mitä ohjelmasi ei tee.

Himmeli666 [03.10.2019 21:51:36]

Lainaa #

Teuro kirjoitti:

Voitko liittää vielä valmiina annetun koodin, johon muutokset pitäisi tehdä?

#include <iostream>
using namespace std;

class Laskin
{
  public:

  int Summa(int eka, int toka);
};

int Laskin::Summa(int eka, int toka)
{
  int summa = eka + toka;
  return summa;
}

// sinun koodisi tulee tähän

int main()
{
  Tulostaja olio;
  olio.Tulosta();
}

Lisäys:

vesikuusi kirjoitti:

Mitä ohjelmasi nyt tekee? Mitä olisit odottanut sen tekevän? Nämä ovat tärkeämpiä seikkoja kuin se, mitä ohjelmasi ei tee.

Tällä hetkellä ohjelma ei tulosta mitään. Herjaa tuota lopun summan tulostusta

void Tulostaja::Tulosta(int Summa)
{
		cout << "Lukujen summa:" <<<< Summa << endl;
}
return Tulostaja;}

Yllä olevan pätkän kun poistan ohjelma tulostaa:
Syötä ensimmäinen kokonaisluku:23
Syötä toinen kokonaisluku:43

Haluan ohjelmani tulostavan:

Himmeli666 kirjoitti:

Syötä ensimmäinen kokonaisluku:33
Syötä toinen kokonaisluku:22
Lukujen summa: 55

Teuro [03.10.2019 22:01:22]

Lainaa #

Toteuta siis tuo Tulostaja-luokka. Luokan Tulosta-metodi pyytää käyttäjältä syötteet. Lisäksi metodissa tulee luoda Laskin-olio, jossa laskeminen tapahtuu. Lopuksi tulostetaan vaadittu lopputeksti.

Ei tosiaan kovin onnistunut esimerkki.

Tronic [04.10.2019 07:49:37]

Lainaa #

Annettu koodi ensinnäkin määrittelee Laskin-luokan, jonka ei ole syytä olla luokka, koska ainoa metodi palauttaa parametriensa summan, eikä esim. käytä jäsenmuuttujia. Toiseksi pyydetään tekemään Tulostaja, joka nimestään huolimatta myös lukee ja laskee sisäisesti.

Mikäli tehtävät ovat tuollaisia, on käymäsi kurssi on jonkun aivonsa Javalla mädättäneen tekemä ja teet itsellesi vain hallaa sitä käymällä. Vaihda parempaan kurssiin, kirjaan tai vaikka https://youtu.be/_bYFu9mBnr4

The Alchemist [04.10.2019 08:13:30]

Lainaa #

Tronic kirjoitti:

Annettu koodi ensinnäkin määrittelee Laskin-luokan, jonka ei ole syytä olla luokka, koska ainoa metodi palauttaa parametriensa summan, eikä esim. käytä jäsenmuuttujia.

Kuten myös ap:n ensimmäinen yritys annetun tehtävän ratkaisemiseksi osoittaa, niin olio-ohjelmoinnin alkeissa on paljon muutakin sisäistettävää ennen kuin aletaan nillittää siitä, missä tilanteissa reaalimaailmassa kuuluisi käyttää tai olla käyttämättä olioita...

Tronic [04.10.2019 08:58:09]

Lainaa #

Linkittämässäni tutoriaalissa luokat mainitaan ensimmäistä kertaa 8h30min ja perintään mennään 10 tunnin kohdalla, mikä onkin järkevämpää kuin Java-tyylin pakottaminen alkeiden yhteydessä.

Epäkäytännöllisen ratkaisun pakollisuutta pitäisi harjoitustehtävissä välttää aina kun mahdollista. Hyvässä tehtävässä on itse ratkaistava ongelma helppo ratkaista uudella opittavalla taidolla, mutta hankala tai mahdoton ilman.

Kun koko ongelma näyttää yhden funktion sisälle kuuluvalta peruskurssin kakkos- tai kolmostehtävältä, on sitä aivan järjetöntä pakottaa edes erillisiksi funktioiksi, saati sitten luokkamuotoon "hyvän ohjelmointityylin vuoksi". Paljon parempiin oppimistuloksiin päästään, kun otetaan ne luokat käyttöön vasta sitten, kun on sen verran isompi ongelma ratkaistavana, että siinä on jotain mieltäkin - alkeiskursseilla tämä tarkoittaa lähinnä aivan kurssin viimeisiä tehtäviä.

Allekirjoittanut on opettanut C++-ohjelmointia Aalto-yliopistossa.

Teuro [04.10.2019 09:01:30]

Lainaa #

Itse tehtävä on todellakin ratkaistavissa paljon helpommin ilman olioita seuraavasti:

#include <iostream>

int Summa(int a, int b);

int main(int argc, char** argv) {
    int luku1, luku2;

    std::cout << "Anna ensimmäinen kokonaisluku: ";
    std::cin >> luku1;

    std::cout << "Anna toinen kokonaisluku: ";
    std::cin >> luku2;

    std::cout << "Lukujen summa: " << Summa(luku1, luku2) << std::endl;
}

int Summa(int a, int b) {
    return (a + b);
}

Koodin toiminta on lukijalle paljon selvempi ja toimii lähes idioottivarmasti. Jos tähän halutaan lisätä Laskin omaksi luokakseen, niin se kannattaa ehkä tehdä seuraavasti:

#include <iostream>

class Laskin {
    int luku1;
    int luku2;
public:
    Laskin(int a, int b) : luku1(a), luku2(b) { }

    int Summa() { return (this->luku1 + this->luku2); }
};

int main(int argc, char** argv) {
    int luku1, luku2;

    std::cout << "Anna ensimmäinen kokonaisluku: ";
    std::cin >> luku1;

    std::cout << "Anna toinen kokonaisluku: ";
    std::cin >> luku2;

    Laskin laskuri(luku1, luku2);

    std::cout << "Lukujen summa: " << laskuri.Summa() << std::endl;
}

Tämä ratkaisu olisi vielä opiskelumielessä ehkä perusteltavissa, joskaan laskinluokalle ei oikein löydy selviä perusteluita. Tästä päässet aika yksinkertaisesti tehtävän vaatimaan muotoon, mutta siinä muunnoksessa menetään ohjelman järkevä rakenne kokonaan, koska tulostinluokka ottaa vastuulleen syötteen lukemista ja laskimen hallinnan. Näiden pitäisi olla jossakin muualla.

The Alchemist [04.10.2019 11:06:20]

Lainaa #

Tronic kirjoitti:

Linkittämässäni tutoriaalissa luokat mainitaan ensimmäistä kertaa 8h30min ja perintään mennään 10 tunnin kohdalla, mikä onkin järkevämpää kuin Java-tyylin pakottaminen alkeiden yhteydessä.

Kuulostaisi kylläkin todella typerältä, mikäli kurssin aiheena olisi olio-ohjelmointi.

Vaikeaa sanoa, mistä tässä todella on kyse, kun ap vain ohimennen mainitsi opiskelevansa c++:n perusteita kertomatta sitä, missä ja millä tavoin hän kieltä opiskelee.

Minua tässä häiritsee se, että funktiot on nimetty kummallisesti. Aivan kuin kurssin vetäjä osaisi itse lähinnä c#:a ja sitten hänet olisi päätetty nimetä c++-kurssin opettajaksi sillä perusteella, että kummankin kielen nimessä on C-kirjain...

Teuro kirjoitti:

Jos tähän halutaan lisätä Laskin omaksi luokakseen, niin se kannattaa ehkä tehdä seuraavasti:

Ei missään nimessä näin huonoa koodia. Miksi laskimesi on rajoitettu kahteen lukuun ja vielä siten, että jokainen "laskin" ymmärtää vain kaksi ctorissa annettua lukua, ja sen jälkeen on käyttökelvoton?

Alla ehdotukseni alkeellisen laskimen toteuttamiseksi. Koodi on kirjoitettu javascriptillä mutta sen on tarkoitus ennemminkin olla pseudokoodia, jonka muuntaminen c++:ksi on suoraviivaista.

class Calculator {
  constructor () {
    this.clear()
  }

  add (number) {
    this.result += number
    return this
  }

  sub (number) {
    this.result -= number
    return this
  }

  clear () {
    this.result = 0
    return this
  }
}

let calculator = new Calculator()
calculator.add(5).add(3).sub(4)

Tronic [06.10.2019 09:41:39]

Lainaa #

The Alchemist kirjoitti:

Tronic kirjoitti:

Linkittämässäni tutoriaalissa luokat mainitaan ensimmäistä kertaa 8h30min ja perintään mennään 10 tunnin kohdalla, mikä onkin järkevämpää kuin Java-tyylin pakottaminen alkeiden yhteydessä.

Kuulostaisi kylläkin todella typerältä, mikäli kurssin aiheena olisi olio-ohjelmointi.

Olio-ohjelmointia ei pitäisi missään tapauksessa peruskursseilla opettaa ainakaan ensimmäisten asioiden joukossa, oli kieli tai tarkoitus mikä hyvänsä. Edellyttää varsin hyvää ohjelmointitaitoa, jotta voi hahmottaa missä tilanteissa OOP:sta ylipäänsä voisi olla etua, eikä asian merkitys näin ollen voi aloittelijalle avautua. Korkeintaan tuotetaan mekaanisesti esimerkkikoodeista johdettua sotkua, kuten ketjun aloituspostauksessa.

Mikäli tavoitteena taas on nimenomaan OOP-paradigman opiskelu, tulisi puolestaan C++ ehkäpä kyseeseen niiden opiskelijoiden kohdalla, joilla on jo ennestään vahva C++-tausta.

The Alchemist [06.10.2019 15:26:45]

Lainaa #

Voihan tuo ihan hyvin olla kurssin loppupuolta. Jos ajatellaan kyseen olevan vaikkapa amk-kurssista, niin onhan lukuvuosi jo sen verran pitkällä, että reilu kuukausi on vähintään ohjelmointiin jo käytetty aikaa.

Metabolix [06.10.2019 21:29:27]

Lainaa #

Jos jatkossa tulee Viopen tehtävissä ongelmia, niin ehdotan kahta ratkaisua: Ensinnäkin lopeta Viope-kurssi, koska se on yksi maailman huonoimmista kursseista. Toiseksi, ratkaisut tehtäviin löytyvät todennäköisesti googlettamalla, koska tehtävät ovat niin ainutlaatuisen huonoa koodia ja ovat tuottaneet monille ongelmia. Esimerkiksi tässä tapauksessa voi syöttää hakuun lainausmerkeissä tuon rivin "int Laskin::Summa(int eka, int toka)", niin löytyy vuosien varrelta keskustelua juuri tästä tehtävästä.

The Alchemist kirjoitti:

Voihan tuo ihan hyvin olla kurssin loppupuolta.

Kurssin loppupuolella luulisi jo henkilön löytävän useampiakin virheitä tuosta kriittisestä koodinpätkästä:

void Tulostaja::Tulosta(int Summa)
{
		cout << "Lukujen summa:" <<<< Summa << endl;
}
return Tulostaja;}

Tuossa viimeinen rivi on täysin väärä: se sijaitsee jo funktion ulkopuolella ja on helppo tunnistaa virheeksi esimerkiksi siitä, että tässä tulee }-merkki, jolle ei ole ollut vastaavaa {-merkkiä. Rivi pitää poistaa. Lisäksi kohdassa <<<< kuuluisi lukea <<.

Muualta koodista nähdään myös, että tällaista Tulosta(int Summa)-jäsenfunktiota ei ole esitelty eikä käytetty, joten tämä funktio pitää poistaa ja tässä oleva cout-rivi voisi olla osana edeltävää Tulosta()-jäsenfunktiota. Tietenkin silloin myös Summa täytyisi siinä laskea esimerkiksi kaavalla (eka+toka).

Himmeli666 kirjoitti:

Koodista oli valmiiksi annettu alku ja loppu. Minun tehtäväksi jäi täydentää tulostaja olio siten, että koodi tulostaa yllä mainitun tulosteen.

Oletko tehnyt vielä ilman luokkia ohjelmaa, jossa kysyttäisiin kaksi lukua ja tulostettaisiin niiden summa? Toivottavasti olet!

Jos katsotaan koodin alkua ja loppua, niin alku on täysin epäolennainen tehtävän ratkaisun kannalta ja lopussa yksinkertaisesti kutsutaan olion jäsenfunktiota Tulostaja::Tulosta(). Loogisesti siis riittää, että kirjoitat tämän yhden funktion sisälle kaiken tarvittavan koodin, jotta saat pyydettyä kaksi lukua ja tulostettua lukujen summan.

Eli jos järkevä ratkaisu itse ongelmaan ilman luokkia näyttää kokonaisuudessaan tältä:

#include <iostream>
int main() {
  int a, b;
  std::cout << "Syötä ensimmäinen kokonaisluku: ";
  std::cin >> a;
  std::cout << "Syötä toinen kokonaisluku: ";
  std::cin >> b;
  std::cout << "Lukujen summa: " << (a + b) << std::endl;
}

Niin nyt tehtävässä ratkaisu näyttää tältä:

#include <iostream>
class Laskin_ja_niin_edelleen;

// ----------------------
// Tästä alkaa oma koodi.

class Tulostaja {
  public:
    void Tulosta();
};

void Tulostaja::Tulosta() {
  int a, b;
  std::cout << "Syötä ensimmäinen kokonaisluku:";
  std::cin >> a;
  std::cout << "Syötä toinen kokonaisluku:";
  std::cin >> b;
  std::cout << "Lukujen summa: " << (a + b) << std::endl;
}

// Tähän loppuu oma koodi.
// ----------------------

int main() {
  Tulostaja olio;
  olio.Tulosta();
}

Kuten on jo edellä kerrottu, tehtävässä annetusta koodin rakenteesta ei todellakaan kannata ottaa mallia omiin ohjelmiin: luokkien käyttö tässä asiassa on turhaa ja typerää, valitut nimet ovat huonoja, ja kokonaisen Laskin-luokan käyttäminen yksinkertaisesti kahden luvun yhteenlaskuun on hulluuden huippu.


Sivun alkuun

Vastaus

Muista lukea kirjoitusohjeet.
Tietoa sivustosta