Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++] pointers en structs

Pagina: 1
Acties:

  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Beste tweakers,

ik ben een beetje met C++ aan het proberen te spelen maar ben nu op een probleem gestoten waar ik niet onmiddellijk uitkom. Ben bezig aan een soort van opdrachtje met een registratiesysteem.

Het gaat over een skiliftsysteem. Het is de bedoeling dat het aantal meters dat iemand op een bepaalde dag heeft afgelegd doormiddel van skiliften te kunnen tellen. Het is ook nodig dat men kan weten hoeveel keren en wie voorbij een bepaalde scanner gekomen is op een bepaalde dag.

Als klassen heb ik een skilift en een skipas. Dan had ik ook nog een struct gemaakt met een skiliftregistratie. Ik dacht nu dat het het makkelijkst was om een vector van die structs bij te houden in zowel de objecten van skilift als van skipas. Zou veel zoekwerk (lees rekenkracht) schelen dan dat ik bijvoorbeeld in mijn main methode een vector bijhield en daarin ging zoeken. Lijkt me ook meer object georiënteerd op deze manier.

Nu is mijn probleem dat ik in die struct eigenlijk een pointer naar mijn skipas en skilift zou willen hebben waar deze bijhoren. Is er een mogelijkheid om dit te doen? Want in principe zou ik de struct eerst moeten declareren zodat ik ze die kan gebruiken in mijn skilift en skipas, langs de andere kant moet ik eerst die skilift en de skipas declareren zodat ik deze kan gebruiken om een pointer naar te maken in mijn struct? Of zit ik helemaal fout?
Als jullie moeten zien wat voor code ik momenteel al heb kan ik die natuurlijk altijd even pasten ;)

Alvast badnkt

Verwijderd

Daarom moet je definitie en declaratie afscheiden in de cpp en header bestanden.

Zo kan bijvoorbeeld de cpp van de skilift de header van het pasje includen en zo kan de cpp van het pasje de header van de skilift includen. (en kunnen ze elkaar gaan gebruiken)

je kan bijvoorbeeld die struct ook in een header afzonderen:

code:
1
2
3
4
5
6
7
8
9
// Pre-declaratie van SkiLift en SkiPas die elders in een header/cpp file staan gedefinieerd
class SkiLift;
class SkiPas;

struct DataStruct
{
   SkiLift* mLift;
   SkiPas* mPas;
}

[ Voor 34% gewijzigd door Verwijderd op 08-04-2008 18:13 ]


  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Ik heb Skilift en Skipas afgezonderd in een header file (mooi zoals het mij geleerd is :))

Ik heb nu dus

main.cpp
Skilift.cpp
Skilift.h
Skipas.cpp
Skipas.h

In main.cpp worden dus skilift.h en skipas.h ge-include. Maar ik zou niet weten waar ik mijn struct dan moet definiëren zodat deze gebruik kunnen maken van de pointers en ik binnen de klassen gebruik kan maken van die struct? :s

Skipas.h
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Skipas {
      public:
             //Constructor
             Skipas();
             Skipas(int skiID, string naamGebruiker);
             
             //Getters
             string getNaam();
             int getSkiID();
             void print();
             void addRegistratie(liftRegistratieS registratie);
             int telMeters(datumS datum);
             
      private:
              int skiID;
              string naamGebruiker;
              vector<liftRegistratieS*> registraties;
};


Skilift.h
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Skilift {
      public:
             //Constructor
             Skilift();
             Skilift(int liftID, string naam, int hoogteBasis, int hoogteEinde, int lengte);
             
             //Getters
             string getNaam();
             int getHoogteVerschil();
             void print();
             
      private:
              int liftID;
              string naam;
              int hoogteBasis;
              int hoogteEinde;
              int lengte;
};

  • muksie
  • Registratie: Mei 2005
  • Laatst online: 26-10 22:24
Die struct geef je ook gewoon een eigen header bestand.

Een struct is voor zover ik weet in C++ gelijk aan een class maar alleen zijn de properties van een struct standaard public en niet private zoals bij een class.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ah, je hebt een dependency probleem. Het was me niet direct duidelijk na het lezen van je topicstart, maar nu je het voorbeeld laat zien snap ik 'm :). Je moet declaraties gebruiken voor je struct, ipv definities. Het verschil is dat je met een declaratie tegen de compiler zegt "er bestaat een X, maar ik weet nog niet hoe ie eruit ziet", terwijl je met een definitie zegt "dit is X".

C++:
1
2
3
4
5
6
7
8
9
10
// declaraties:
class Skipas;
class Skilift;

// definitie:
struct MijnStruct
{
    Skipas * skipas;
    Skilift * skilift;
};

Zoals je ziet, voor de definitie van MijnStruct heb je niet de definities van Skipas en Skilift nodig, alleen de declaraties. Dit geldt altijd voor pointers, references, functie parameters en functie return-waarden. Op het moment dat je een type als value (dus geen pointer of reference) in je class definieert, of als je je class ervan wilt laten overerven, dan pas heb je de definitie nodig (en ook dan pas include je de relevante header)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Ok bedankt, dat is gelukt. Nu heb ik echter nog een zeer vreemd probleem. Kan er echt niet aan uit.

Ik heb een struct datumS en een struct liftRegistratieS

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct datumS
{
    int dag;
    int maand;
    int jaar;
} datumS;

class Skipas;
class Skilift;

typedef struct liftRegistratieS
{
    datumS datum;
    Skipas * skipas;
    Skilift * skilift;
} liftRegistratieS;


Nu vraag ik eerst een datum op met behulp van

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
datumS vraagDatum()
{
     int dag, maand, jaar;
     
     cout << "Gelieve een datum in te geven" << endl;
     cout << "Dag: ";
     cin >> dag;
     cout << "Maand: ";
     cin >> maand;
     cout << "Jaar; ";
     cin >> jaar;
     
     datumS datum = {dag, maand, jaar};
     
     return datum;         
}


Geen probleem. Maak ik er een liftRegistratieS van met behulp van:

code:
1
2
3
4
5
6
7
8
void Skipas::addRegistratie(liftRegistratieS registratie)
{
     registraties.push_back(&registratie);
     
     liftRegistratieS *registratiee;
     registratiee = registraties.at(0);
     cout << registratiee->datum.dag << endl;
}


Ook geen probleem. Die cout geeft mooi de waarde terug van die dag.
Als ik nu echter

code:
1
2
3
4
5
6
7
liftRegistratieS *registratie;
    for(int i=0;i < registraties.size(); i++)
    {
        registratie = registraties.at(i);
        
        cout << registratie->datum.dag <<endl
   }

uitvoer dan krijg ik voor dag een of andere integer in de waarde van 22xxx. (Wel elke keer dezelfde). Vind het zeer vreemd want maand en jaar blijven wel ok. Enig idee iemand?

Alvast bedankt maar weer :)

Edit:
Denk dat ik het gevonden heb. Aangezien de aangemaakte structs van liftRegistratieS nergens vast een array werder gestopt worden die geheugenplaatsen terug opengemaakt en dus wordt de geheugenplaats van die datum terug vrijgegeven? Vind het wel vreemd dat hij steeds weer met dezelfde waarde wordt overschreven.. Maarja van dat geheugenbeheer ken ik te weinig denk ik. Nu sla ik dus niet de pointers maar echte de objecten op in mijn vector.
Nu alleen nog zorgen dat ik in mijn skilift klasse ook kan werken met die liftregistraties.

Bedankt voor de hulp!

[ Voor 14% gewijzigd door Thomson op 08-04-2008 23:01 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Thomson schreef op dinsdag 08 april 2008 @ 22:05:
Ok bedankt, dat is gelukt. Nu heb ik echter nog een zeer vreemd probleem. Kan er echt niet aan uit.

Ik heb een struct datumS en een struct liftRegistratieS

code:
1
2
3
4
5
6
typedef struct datumS
{
    int dag;
    int maand;
    int jaar;
} datumS;
Typedefs hoef je niet te gebruiken, dat komt uit C waar een struct niet automatisch een typename introduceert. In C++ is dat wel het geval (net als bij class), en de typedef is dus zinloos :).
code:
1
2
3
void Skipas::addRegistratie(liftRegistratieS registratie)
{
     registraties.push_back(&registratie);
Hier ga je de mist in. 'registratie' is een lokale variabele, die staat dus op de stack. De stack is 'vluchtig', oftewel, je variabele houdt op te bestaan zodra je weer uit de functie gaat. Je stopt echter het adres van de variabele in de vector. Je kunt je dus voorstellen dat je op een later tijdstip onzin-informatie uit gaat lezen, want daar waar de variabele eerst stond kan nu heel iets anders staan.

Als je per se pointers op wilt slaan moet je eerst een liftRegistratieS alloceren op de heap (mbv 'new'), maar handiger is om gewoon values in de vector te stoppen. Dus std::vector<leftRegistratieS>, en registraties.push_back(registratie).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Ja, ik had het dus net door. Ik dacht even geheugen gaan te besparen door enkel de pointers op te slaan omdat ik binnen 2 objecten 1 en dezelfde struct wou opslaan. Natuurlijk moet ik er voor zorgen dat 1 van de twee ook zorgt dat dat geheugen vrijblijft natuurlijk. Doh. Hartelijk dank voor je hulp!

Nu heb ik echter wel nog een probleempje met mijn header files. Ik krijg het niet voor elkaar om die structs in zowel mijn skipas als skilift te krijgen.

Heb nu zoiets
code:
1
2
3
4
5
6
class Skipas;
class Skilift;

#include "structs.h"
#include "Skilift.h"
#include "Skipas.h"

Blijkbaar kunnen mijn structs nu echter niet gebruikt worden binnen de classes die gedeclareerd zijn in de andere header files. Hier kom ik zelf normaal wel achter, tenzij iemand toevallig snel de oplossing weet (ligt waarschijnlijk wel voor de hand)

Groeten

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een goede regel om aan te houden is dat headers op zichzelf compileerbaar moeten zijn. Oftewel, als iemand die header include, dan moet die persoon niet ineens allemaal errors om z'n oren krijgen omdat ie iets is vergeten te doen vóór het includen van die header.

Welnu, struct.h is degene die de declaraties van Skipas en Skilift nodig heeft, dus het lijkt me handig om die declaraties dan ook daar in te zetten :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Ok klinkt logisch

structs.h:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using namespace std;

class Skipas;
class Skilift;

struct Datum
{
    int dag;
    int maand;
    int jaar;
};

struct LiftRegistratie
{
    Datum datum;
    Skipas * skipas;
    Skilift * skilift;
};


Heeft het probleem echter nog nie opgelost. Het lijkt net of die andere header files niets af weten van het feit dat structs.h reeds geïnclude is.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat moet je dan ook voorkomen met header guards

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Thomson
  • Registratie: Februari 2003
  • Laatst online: 02-01 10:11
Jij ben de man! C++ en zijn regeltjes, ik heb nog veel te leren :)
Bedankt!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
Owhja, een complete namespace in je huidige namespace trekken door
C++:
1
using namespace std;


in een header file te zetten is niet verstandig.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Idd, dat doet het hele nut van namespaces weer teniet. Zelf typ ik std:: sowieso altijd gewoon voluit. Is ook meteen duidelijk waar alles vandaan komt.

[ Voor 47% gewijzigd door .oisyn op 09-04-2008 15:25 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:37
C++:
1
std::cerr << x << std::endl;

... typen wordt een beetje vervelend bij het debuggen. ;)

  • writser
  • Registratie: Mei 2000
  • Laatst online: 18-11 12:05
Soultaker schreef op woensdag 09 april 2008 @ 15:41:
C++:
1
std::cerr << x << std::endl;

... typen wordt een beetje vervelend bij het debuggen. ;)
Je kan toch ook een paar losse dingen importen?

C++:
1
using std::cerr;


Of is dat ook niet netjes?

Onvoorstelbaar!


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

a) welke zichzelf respecterende programmeur doet er nou aan output debugging? ;)
b) daar maak je een macro van, zodat je het conditioneel aan en uit kan zetten
c) zo typ ik het idd altijd ja :)

[ Voor 27% gewijzigd door .oisyn op 09-04-2008 15:47 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:37
writser schreef op woensdag 09 april 2008 @ 15:46:
Je kan toch ook een paar losse dingen importen?
C++:
1
using std::cerr;
Inderdaad, dat doe ik ook vaak. Als ik door een hele module bijvoorbeeld strings en vectors gebruik, dan importeer ik die liever expliciet in mijn namespace dan dat ik de de code volspam met std::.. referenties. Maar goed, voor dingen die je maar één of twee keer gebruikt is dat overkill.

Ik wilde alleen maar aangeven dat het importeren features uit de std:: namespace niet per se slecht is. De hele std:: namespace is niet heel netjes, maar voor een kleine source file die toevallig veel verschillende standaardfuncties nodig heeft, kan ik me voorstellen dat het beter is dan de alternatieven.

(Als het goed is, horen er alleen maar standaarddeclaraties in de std-namespace te zitten toch?)

[ Voor 29% gewijzigd door Soultaker op 09-04-2008 20:10 ]


  • Amotea
  • Registratie: Mei 2004
  • Laatst online: 23-01 17:45
Vooral met iterators en pairs enz. vind ik dat het onoverzichtelijk kan worden.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
Dan nog zou ik het niet in de header doen, dat betekent dat alle sources die de header includen dus ook meteen de hele namespace erin trekken. Lijkt me een beetje de plank misslaan .....

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op woensdag 09 april 2008 @ 20:08:
(Als het goed is, horen er alleen maar standaarddeclaraties in de std-namespace te zitten toch?)
En evt. names reserved for implementation (beginnend met een underscore en een hoofdletter, of waar twee opeenvolgende underscores in staan)
Amotea schreef op woensdag 09 april 2008 @ 23:11:
Vooral met iterators en pairs enz. vind ik dat het onoverzichtelijk kan worden.
Daar heb je typedefs voor. Sowieso, wil je beweren dat een map<MyTypeA, MyTypeB>::iterator zo ontzettend veel overzichtelijker is dan een std::map<MyTypeA, MyTypeB>::iterator? Met een typedef voor de map krijg je MyMap::iterator, dat is nou wél een verschil. Bovendien hoef je niet op ontzettend veel plekken je code aan te passen op het moment dat je besluit dat je map eigenlijk een andere allocator moet hebben oid.

[ Voor 69% gewijzigd door .oisyn op 10-04-2008 10:44 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:37
Ik vind het altijd wel stom dat als ik een vector van pairs van strings ofzo heb (niet echt far-fetched i.m.o) het praktisch onmogelijk is om een for-loop die erover itereert op één regel te krijgen:
C:
1
for (std::vector<std::pair<std::string, std::string> >::const_iterator i = v.begin(); i != v.end(); ++i)

Dat zijn meer dan honderd fucking karakters! En dat is zonder enige indentation en met identifiers van minimale lengte! De typedeclaratie van de iterator is veel te lang; die std::-prefix weghalen scheelt dan toch 20 karakters (nog niet zaligmakend i.m.o, maar toch).

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

C++:
1
for (StringPairVector::const_iterator i = v.begin(); i != v.end(); ++i)

Maar goed, het is sowieso wachten op C++0x's auto ;)
C++:
1
for (auto i = v.begin(); i != v.end(); ++i)

Of nog beter, foreach
C++:
1
foreach(auto& x : v)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1