Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Olio-ohjelmointia C++:lla, osa 2

Sivun loppuun

jsbasic [08.06.2010 22:08:50]

#

Miten luokan metodin voi kirjoittaa niin että se ottaa parametreina tietyn luokan olion? Ei siis primitiivityyppiä. Kannattaako käyttää osoittimia?

alottelijaa [08.06.2010 22:12:06]

#

Mitä koitat tehdä? Voit antaa olion ihan normaalisti parametrinä jos haluat vain sen sisällön mutta jos haluat käsitellä juuri jotain tiettyä oliota käytä viittausta.

jsbasic [08.06.2010 22:19:50]

#

Haluaisin tietää miten olio annetaan normaalisti parametrinä. (Vaikka ohjelmoija ei sanan varsinaisessa merkityksessä "anna oliota", vaan "kirjoittaa luokan metodin niin että se ottaa parametreina tietyn luokan olion".)

Oma veikkaus on näistä ylin, mutta en saanut sitä toimimaan:

void foo(MyClass obj) {}
void foo(MyClass* obj){}
void foo(MyClass& obj){}
void foo(MyClass & obj){}
void foo(MyClass &obj){}

error: no matching function for call to `MyClass ::MyClass ()'

alottelijaa [08.06.2010 23:09:06]

#

//main.cpp
#include "luokka.h"
#include "luokka2.h"

int main()
{
    Luokka a;
    Luokka2 b;

    b.kutsuAata(a);

    return 0;
}

//luokka.h
class Luokka
{
    int z;
    public:
      void testi() { z = 55; }
};

//luokka2.h
class Luokka2
{
    public:
       void kutsuAata(Luokka a) { a.testi(); }
};

jotain tuollaista voisi toimia. Jos haluat tehdä luokasta pointerin niin taitavat toimia näin:

void foo (Luokka *obj) {} //toiminee
void foo (Luokka &obj) {} //toiminee myös, mutta joutuu käyttämään *obj kun haluaa päästä arvoon käsiksi

//const:n kanssa en ole ihan varma mutta käsittääkseni

void foo (const Luokka *obj) //arvo on const, äkkiä ajatellen ei taida toimia pointerin kanssa?
void foo (Luokka *obj const) //osoitin on const, varmaankin toimii
void foo (const Luokka *obj const) //osoitin ja arvo on const varmaankin toimii?

Voiko joku korjata jos meni jotain väärin siitä on jo puoli vuotta kun viimeksi edes koskin c++:aan.

EDIT: nähtävästi koitit antaa konstruktorille sitä luokkaa? MyClass::MyClass() virheestä päätellen. Voit tehdä vaikka näin ja en kirjoita näin pitkiä viestejä enää :D

MyClass::MyClass() {
//koodia, jos aiot luoda luokan antamatta parametrinä luokkaa tee tämmöinen
}

MyClass::MyClass(Luokka obj) {
//koodia, muista pistää tämäkin funktio luokan esittelyyn (header fileen siis)
}

trilog [08.06.2010 23:33:58]

#

jsbasic kirjoitti:

Haluaisin tietää miten olio annetaan normaalisti parametrinä. (Vaikka ohjelmoija ei sanan varsinaisessa merkityksessä "anna oliota", vaan "kirjoittaa luokan metodin niin että se ottaa parametreina tietyn luokan olion".)

Samalla tavalla kuin mikä tahansa muukin parametri (ks. C++-oppaan 5. osio).

void funktio(Luokka obj); // Tekee parametrina välitetystä luokasta kopion (kutsuu kopiointikonstruktoria).
void funktio(Luokka& obj); // Instanssi välitetään viittauksena alkuperäiseen luokkaan (= muutokset näkyvät ulkopuolelle).
void funktio(const Luokka& obj); // Instanssi välitetään viittauksena alkuperäiseen luokkaan, mutta const estää muutokset (pääsääntöisesti).

Osoittimenakin sen voi välittää, joka toimii pääsääntöisesti samalla tavalla kuin viittaus (muutamaa tärkeää eroa lukuun ottamatta).

Tässä vaiheessa on tärkeä ymmärtää osoittimen ja vittauksen ero, sekä constin merkitys. Suosittelen lukemaan täältä löytyvän C++-oppaan kokonaan läpi.

jsbasic kirjoitti:

error: no matching function for call to `MyClass ::MyClass ()'

Virhe johtuu siitä, että et ole määritellyt luokalle MyClass konstruktoria, joka ei ota parametreja, jolloin sitä ei voida kutsua. Eli esimerkiksi seuraava ei onnistu:

MyClass luokka;

Metabolix [09.06.2010 09:19:18]

#

Jos on tarkoitus, että arvo täytyy aina antaa, kannattaa käyttää viittausta (ei osoitinta), jotta NULL-arvoa ei voi helposti antaa vahingossa. Const-viittaus on kopiointia parempi, ellei olio ole erittäin pieni ja triviaali (pelkkiä primitiiviarvoja sisältävä). Muista const aina silloin, kun oliota ei ole tarkoitus muokata funktiossa!

jsbasic [09.06.2010 09:34:29]

#

trilog kirjoitti:

Virhe johtuu siitä, että et ole määritellyt luokalle MyClass konstruktoria, joka ei ota parametreja, jolloin sitä ei voida kutsua.

Miksi se kutsuu konstruktoria?

Eikö tämä tarkoita Luokka-konstruktorin parametrin arvoa. Miksi kaikki tulkitaan MyClass luokan konstruktoriksi?

Luokka(MyClass obj) {} // = MyClass luokan kostruktori
Luokka(MyClass& obj) {} // = MyClass luokan kostruktori

Haluan olioon pysyvän kytkennän toiseen olioon. Olen kyllä kutsunut konstuktoria luokan "juuressa", eli en metodissa. En tiedä voiko kontruktoria kutsua juuressa, mutta jotenkin kääntäjälle on tiedotettava että yhteistä muuttujaa halutaan käyttää kaikissa metodeissa.

private:
   //Näistä kaikki valittavat jotain
   Luokka olio; //Valittaa toisaalla ettei konstrukroria ole. Ei olekaan.
   Luokka olio(1,2); //expected `,' or `...' before numeric constant
   Luokka olio=new Luokka(1,2); //`new' cannot appear in a constant-expression

trilog [09.06.2010 10:36:02]

#

Suosittelen laittamaan näkyville luokkamäärittelyt ja niiden toteutukset (ainakin merkitseviltä osin), sillä nykysillä tiedoilla on vaikea antaa hyviä vastauksia (arvaten, että et ole määritellyt oikeita konstruktoreja). Älä myöskään yritä luoda oliota luokan jäsenmuuttujan määrittelyssä, vaan tee se isäntäluokan konstruktorissa.

jsbasic [09.06.2010 11:01:13]

#

trilog kirjoitti:

Älä myöskään yritä luoda oliota luokan jäsenmuuttujan määrittelyssä...

Tarkoitat olion luomisella ilmeisesti konstruktorin kutsumista. En halunnutkaan tehdä sitä jäsenmuuttujan määrittelyssä vaan esim. siellä isännän konstruktorissa. Mutta joka tapauksessa muuttujan olemassa olo on ilmoitettava jäsenmuuttujan määrittelyssä? Tehdäänkö se sitten .h -tiedostossa?

Tässä se luokka jonka yritin syöttää parametrina ja tallettaa toiseen olioon:

luokkamäärittely:

#ifndef CPISTE_DEF
#define CPISTE_DEF

/** Peliobjektin sijainti maailmassa. */
class cPiste {
	public:
        /** Tulostaa sijainnin tekstinä*/
        void tulosta ();
        void aseta(int nx, int ny);
        cPiste(int x, int y);
        ~cPiste();
	private:
        int x,y;
};

#endif

toteutus:

#include <stdio.h>
#include "koe.h"

void cPiste::tulosta() { printf("Sijaitsee kohdassa (%d,%d)\n", x, y);}
void cPiste::aseta(int nx, int ny) { x = nx; y = ny; }

cPiste::cPiste(int x=255, int y=255) {
   aseta(x, y);
}

cPiste::~cPiste() {
    x=y=0;
}

Metabolix [09.06.2010 11:07:18]

#

Eihän tuossa koodissa ole mitään vikaa. Vika on siinä, miten yrität tuota luokkaa käyttää.

Oletusargumentit kannattaisi laittaa jo funktion esittelyyn, määrittelyssä niistä ei ole paljon iloa.

jsbasic [09.06.2010 11:20:58]

#

Niin, en saa tehdyksi toiseen luokkaan jäsenmuuttujaa joka on tämän luokan tyyppiä ja jonka voisi asettaa metodin kautta. Tosin se "isäntäluokka" ei ole määritelty .h -tyyliin...

class Luokka {
    public:
      Luokka(cPiste p) {
        piste=p;
      }
    private:
      cPiste piste;
};

error: no matching function for call to `cPiste::cPiste()'

jsbasic [09.06.2010 12:30:18]

#

Tämä toimii kyllä täysin:

class Luokka {
    public:
      Luokka() {
        cPiste piste(2,3);
      }
};

karwis [09.06.2010 12:55:42]

#

"error: no matching function for call to `cPiste::cPiste()'"

Luokan cPiste oletusmuodostin cPiste::cPiste(int x, int y) vaatii kaksi kokonaislukua parametreiksi. Koitat tuossa luoda oliota antamatta noita parametreja niin siitä se herjaa. Lisää tuonne cPiste-luokkaan muodostin cPiste::cPiste();

Metabolix [09.06.2010 13:00:51]

#

Ongelma on juuri noissa oletusargumenteissa, joista jo huomautin. Muista, että kääntäjä ei tiedä toisten .cpp-tiedostojen sisällöstä, vaan kaikki olennainen (kuten nuo) täytyy kertoa .h-tiedostoissa.

jsbasic [09.06.2010 13:11:50]

#

En ymmärrä... Jäsenmuuttuja tuossa valittaa. Kun tuon konstruktorikutsun ottaa pois, toimii hyvin.

class Luokka {
    public:
      Luokka(cPiste piste) {
        piste.tulosta();
      }
    private:
      cPiste piste(2,3); // <- error: expected identifier before numeric constant.
      //Miten voin siis esitellä jäsenmuuttujan
};

int main(void)
{
    cPiste piste(1,1);
    Luokka olio(piste);
}

trilog [09.06.2010 13:24:08]

#

Siirrä oletusargumentit konstruktorin esittelyyn:

class cPiste {
  public:
    cPiste(int x=255, int y=255);
/*
 *
 */
};

Toteutus tulee silloin muotoon:

cPiste::cPiste(int x, int y) {/* toteutus */}

jsbasic [09.06.2010 13:44:24]

#

Hienoa, alkoi toimia. Mutta vielä ihmettelen miksi konstruktiota pitää kutsua kahteen kertaan. Mihin tarvitsen oletusargumenteilla luotua oliota? :p Javassa voi luoda tyhjän muuttujan, jolla siis on vain luokan tyyppi mutta arvo on null.

Metabolix [09.06.2010 14:11:21]

#

Tässä on vielä esimerkki jäsenmuuttujan alustuksesta (ja siis konstruktorin kutsumisesta):

class A {
  // Seuraavalla rivillä ei vielä tapahdu mitään.
  int x;

  // Muodostimessa alustetaan jäsen x:
  // - parametrien _x ja _y perusteella
  A(int _x, int _y): x(_x + _y) {
  }
  // - parametrin _x perusteella; lukua 10 käytetään, jos argumentti puuttuu.
  A(int _x = 10): x(_x) {
  }
};

class B {
  // Seuraavalla rivillä ei vielä tapahdu mitään.
  A a;

  // B:n muodostimessa muodostetaan jäsen a:
  // - vanhasta A-oliosta.
  B(A const& _a): a(_a) {
  }
  // - annetun luvun perusteella.
  B(int x): a(x) {
  }
  // - automaattisesti oletusmuodostimella, tässä tapauksessa A(10).
  B() {
  }
};

Chiman [09.06.2010 14:12:47]

#

jsbasic kirjoitti:

private:
  cPiste piste(2,3); // <- error: expected identifier before numeric constant.
  //Miten voin siis esitellä jäsenmuuttujan

Näin?

private:
  cPiste piste;

Pieni demo: http://codepad.org/BeDJfaBE (käytännön syistä tuossa koko koodi yhdessä pötkössä, ei kannata matkia)

jsbasic [09.06.2010 15:34:30]

#

Chiman kirjoitti:

private:
      cPiste piste;

Juuri niin, huomasin sen jo.

Metabolix kirjoitti:

Tässä on vielä esimerkki jäsenmuuttujan alustuksesta (ja siis konstruktorin kutsumisesta):

Ymmärrän. Merkintätapa on minulle uusi. Näppärän näköistä. Tuo tulee siis esittelyyn. Jos konstruktorin pitää asettaa useita jäseniä, ne voi erottaa pilkulla:

B(int x, int y): a(x), b(y) {
 }

Sivun alkuun

Vastaus

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

Tietoa sivustosta