Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Lisää olio-o. vaikeuksia

tkok [03.02.2009 10:04:32]

#

Moi taas.
Olen siis saanut osoittelulla ja viittailulla ja olionnilla ohjelmani solmuun:
Eli erroria heittää rivi:

if(KaupunkiTaulu[i].Paikka.LaskeEtaisyys(Testi) <= r){

Errori:
C:\Projektit\New Folder\Pgrid\main.cpp|104|error: request for member `Paikka' in `*((+(((unsigned int)i) * 4u)) + KaupunkiTaulu)', which is of non-class type `City*'|


Tässä listattuna osa koodista:

#include <iostream>
#include <math.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
using namespace std;
void KirjoitaTeksti(string teksti);
int YhteysLaskuri = 1;
int KaupunkiLaskuri = 0;
double r=16;

SDL_Event Tapahtuma;

class Piste{//piste olio, mm etäisyyslaskurilla
    public:
        int x;
        int y;
    double LaskeEtaisyys(Piste P){
        return sqrt((x-P.x)*(x-P.x)+(y-P.y)*(y-P.y));
    }
    void LueHiiri(){
        bool OK=false;
        while(!OK){
            if( Tapahtuma.type == SDL_MOUSEBUTTONDOWN )
            {
                //Vasemmasta
                if( Tapahtuma.button.button == SDL_BUTTON_LEFT )
                {
                    //otetaan x ja y
                    x = Tapahtuma.button.x;
                    y = Tapahtuma.button.y;
                    OK = true;
                }
            }
        }
    }
};
class City{//luokka kaupungeille: Sijainti ja nimi ja yhteydet joita kaupungilla on
    public:
        City();//kutsutaan muodostinta
        void City::UusiCity();
        Piste Paikka;
        string Nimi;
        int yhteys[6];
        int City::PisteKaupungiksi(Piste Testi, City *KaupunkiTaulu[43]);
};
class Yhteys{ // yhteys olio: hinta ja kaupungit joiden välissä yhteys on ja myös pisteet joista piirretään
    public:
    int Hinta;
    int City1;
    int City2;
    Piste pisteet[2];
    Yhteys();
    void UusiYhteys();
    int KysyHinta();
};

//Taulukot datan säilömistä varten:
City Kaupungit[43];
Yhteys Yhteydet[260];

int City::PisteKaupungiksi(Piste Testi, City *KaupunkiTaulu[]){//Katsotaan minkä kaupungin alueella piste on
    int Tulos=0;
    for(int i = 0;  i<KaupunkiLaskuri; i++){
        if(KaupunkiTaulu[i].Paikka.LaskeEtaisyys(Testi) <= r){//jos piste korkeintaan säteen päässä on kyseinen kaupunki valittu
            Tulos = i;
        }
    }
    return Tulos;
}

EDIT1: Kutsun PisteKaupungiksi funktiota errorisilla kutsuilla:

void Yhteys::UusiYhteys(){//Kun pyydetään uutta yhteyttä
    Piste Hiiri; //Luodaan piste hiirren sijainnin muistamiseksi
    Hinta = Yhteys::KysyHinta(); //kysytään käyttä jältä int hinta
    KirjoitaTeksti("Valitse Kaupunki 1"); //kerrotaan mitä halutaan
    City1=City::PisteKaupungiksi(Hiiri.LueHiiri, &Kaupungit); //kaupunki yksi on kaupunki joka on alle r(=säde) päässä klikatusta kohdasta, kaupunki valitaan kaupungit taulukosta
    KirjoitaTeksti("Valitse Kaupunki 2");
    City2=City::PisteKaupungiksi(Hiiri.LueHiiri(), &Kaupungit);
}

C:\Projektit\New Folder\Pgrid\main.cpp|121|error: no matching function for call to `City::PisteKaupungiksi(<unknown type>, City (*)[43])'|
C:\Projektit\New Folder\Pgrid\main.cpp|101|note: candidates are: int City::PisteKaupungiksi(Piste, City**)|
C:\Projektit\New Folder\Pgrid\main.cpp|123|error: invalid use of void expression|

EDIT2: vähän kommentteja

Metabolix [03.02.2009 10:53:04]

#

Opettele katsomaan virheilmoitusten rivinumeroita.

int City::PisteKaupungiksi(Piste Testi, City *KaupunkiTaulu[43]);

Ensimmäinen mainitsemasi virheilmoitus johtuu tästä. Annat parametriksi taulukollisen osoittimia. KaupunkiTaulu[i] on siis osoitin, jolloin oikea merkintä olisi KaupunkiTaulu[i]->jasen eikä KaupunkiTaulu[i].jasen. Tällä kertaa virhe on kuitenkin tuossa määrittelyssä, koska koodissa yrität antaa taulukollisen olioita (ts. yhden osoittimen) ja näin onkin järkevämpi tehdä. Ota hakasulut kokonaan pois.

City1=City::PisteKaupungiksi(Hiiri.LueHiiri, &Kaupungit);

Toinen virheilmoitus ja siihen liittyvä huomautus koskevat tätä. Ensinnäkin Hiiri.LueHiiri-kohdasta puuttuvat sulut. Yrität siis antaa parametrina epämääräisen funktion. Ota myös & pois. Kuten yllä todettiin, et ole antamassa osoitinta taulukkoon vaan taulukon, joka jo itsessään on siis osoitin olioihin.

City2=City::PisteKaupungiksi(Hiiri.LueHiiri(), &Kaupungit);

Viimeinen virheilmoitus tulee tästä, ja kuten siinä selvästi sanotaan, yrität tehdä void-arvolla jotain sopimatonta. Tarkemmin sanoen yrität antaa Piste-parametrina void-arvon, koska LueHiiri on void-funktio. Joko sinun täytyy siirtää LueHiiri-kutsu ylemmälle riville ja antaa tässä pelkkä Hiiri, tai voit palauttaa kyseisestä funktiosta viittauksen olioon itseensä:
Piste& LueHiiri() { ... return *this; }

Lisäksi LueHiiri-funktio on ilmiselvästi virheellinen. Mihin se Tapahtuma kesken funktion muuttuisi? Joudut siis ikuiseen silmukkaan. Muutenkin vaikuttaa aika erikoiselta, että jumittaisit tuossa koko ohjelman, kunnes nappia painetaan. Ehkä sinun kannattaa suunnitella rakennetta hieman uudestaan.

tkok [03.02.2009 11:13:54]

#

Kiitos avuista. Ja tämä ohjelma on vain kenttäeditori itselleni, jolloin tiedän että ohjelman on tarkoitus jumittaa kunnes klikataan. Ohjelma antaa viestin "valitse kaupunki" ennen kun mennään hiiren klikkaus silmukkaan ja sitten jää odottelemaan että painetaan hiirellä. Ja kyllä tämä rakenne tästä muotoutuu sitten kun pääsen vähän eteenpäin, siitä tulee tietty ylimääräistä hommaa.

Nyt tein ehdottamasi muutokset, siis []-sulkeet pois &-merkki pois ja () lisää ja siirsin Hiiri.LueHiiri() tapahtumaan ennen kutsua ja laitoin kutsuun pelkän Hiiri, Kaupungit. Lisäsin myös luehiiri funktioon SDL_PollEvent(&Tapahtuma);. Nyt kuitenkin tulee vielä jotain objektin puuttumis erroria näistä kutsuista:

void Yhteys::UusiYhteys(){
    Piste Hiiri;
    Hinta = Yhteys::KysyHinta();
    KirjoitaTeksti("Valitse Kaupunki 1");
    Hiiri.LueHiiri();
    City1=City::PisteKaupungiksi(Hiiri, Kaupungit);
    KirjoitaTeksti("Valitse Kaupunki 2");
    Hiiri.LueHiiri();
    City2=City::PisteKaupungiksi(Hiiri, Kaupungit);
}

C:\Projektit\New Folder\Pgrid\main.cpp||In member function `void Yhteys::UusiYhteys()':|
C:\Projektit\New Folder\Pgrid\main.cpp|123|error: cannot call member function `int City::PisteKaupungiksi(Piste, City*)' without object|
C:\Projektit\New Folder\Pgrid\main.cpp|126|error: cannot call member function `int City::PisteKaupungiksi(Piste, City*)' without object|
||=== Build finished: 2 errors, 0 warnings ===|

Metabolix [03.02.2009 13:30:46]

#

Niin, aivan. Jotta voisit kutsua PisteKaupungiksi-funktiota ilman City-objektia, sen täytyy olla staattinen (jolloin sitä taas ei voi kutsua objektin kanssa).

class A {
public:
  int luku;
  static int staattinen_luku;
  static int staattinen() {
    return staattinen_luku; // voidaan käyttää vain staattisia jäseniä
  }
  int lasku() {
    return luku + staattinen_luku; // voidaan käyttää omia JA staattisia muuttujia
  }
};
int A::staattinen_luku; // staattinen muuttuja pitää määritellä vielä erikseen

#include <iostream>

int main() {
  A a, b;

  // Jokainen näistä muuttaa samaa, yhteistä jäsentä:
  A::staattinen_luku = 30;
  a.staattinen_luku = 40;
  b.staattinen_luku = 50;
  std::cout << A::staattinen() << "\n"; // 50

  // Joka instanssilla (tässä a ja b) on oma luku-jäsen
  a.luku = 10;
  b.luku = 20;
  std::cout << a.lasku() << "\n"; // 10 + 50 == 60
  std::cout << b.lasku() << "\n"; // 20 + 50 == 70

  // A::luku = 5; // Virhe, luku on luokan instanssin asia!
  return 0;
}

tkok kirjoitti:

Lisäsin myös luehiiri funktioon SDL_PollEvent(&Tapahtuma);

SDL_WaitEvent on parempi tuohon, koska se osaa nukkua tapahtumaa odottaessaan. On tyhmää käyttää 100% prosessoritehosta odottamiseen, kun mitään ei tapahdu.

while (SDL_WaitEvent(&Tapahtuma)) {
  if (Tapahtuma.type == SDL_MOUSEBUTTONDOWN) {
    if (Tapahtuma.button.button == SDL_BUTTON_LEFT) {
      break; // nappi tuli, pois silmukasta
    }
  }
}
// Nyt silmukan jälkeen Tapahtuma on se viimeisin klikkaus, joten otetaan arvot.

tkok [03.02.2009 15:14:09]

#

Metabolix kirjoitti:

Niin, aivan. Jotta voisit kutsua PisteKaupungiksi-funktiota ilman City-objektia, sen täytyy olla staattinen (jolloin sitä taas ei voi kutsua objektin kanssa).

class A {
- -

tkok kirjoitti:

Lisäsin myös luehiiri funktioon SDL_PollEvent(&Tapahtuma);

SDL_WaitEvent on parempi tuohon, koska se osaa nukkua tapahtumaa odottaessaan. On tyhmää käyttää 100% prosessoritehosta odottamiseen, kun mitään ei tapahdu.

Joopajoo vähän menee ohi, en tiedä mitä noi staattiset ja nonstaattiset oikeestaan tekee, mut koitan oppia iltaan mennessä. Tällä hetkellä oliot ja osoittimet tuottavat tarpeeksi töitä :P Saako tätä mitenkään sopimaan siihen mun tekemän koodin rakenteeseen, vai teenkö jollain toisella tavalla koko kaupungin valinta funktion?

Metabolix [03.02.2009 15:40:54]

#

Ota se pois luokan sisältä (ja tietysti kaikki City::-kohdat vastaavasti pois).

Vastaus

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

Tietoa sivustosta