Miten luokan metodin voi kirjoittaa niin että se ottaa parametreina tietyn luokan olion? Ei siis primitiivityyppiä. Kannattaako käyttää osoittimia?
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.
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 ()'
//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) }
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ä const
in 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;
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!
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
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.
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; }
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.
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()'
Tämä toimii kyllä täysin:
class Luokka { public: Luokka() { cPiste piste(2,3); } };
"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();
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.
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); }
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 */}
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.
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() { } };
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)
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) { }
Aihe on jo aika vanha, joten et voi enää vastata siihen.