[C++]hoe geef ik een vector van structs mee aan een functie?

Pagina: 1
Acties:
  • 201 views sinds 30-01-2008
  • Reageer

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 19-10-2025
beetje vage topic titel, maar hier komt de uitleg:

ik heb gezellig in een programma een structure gemaakt, en deze heb ik gevult.

nu heb ik een vector waar die structure weer in zit.
die vector is globaal gedefineerd, en kan lekker overal geedit worden:

C++:
1
2
3
4
5
6
7
8
struct klantenBestand {

..

};

vector<klantenBestand> v_structs;
klantenBestand record;


nu wil ik meerde van dit soort programmatjes maken, die met zijn alle gebruik maken van een globale functie (die dus geinclude word).
deze functie heet 'outputBinaryFile' en (je raad het al) hij schrijft de vector/structs weg in een binary file.

nu wil ik dus mijn globaal gedefineerde vector meegeven aan die functie (samen met -duh- een filename)

mijn functieaanroep zou dan zoiets worden als:
code:
1
outputBinaryFile("file.bin",v_structs);


normale manier om data uit vector te lezen is als volgt:
C++:
1
2
3
4
for (int c=0; c<v_structs.size(); c++) {
  record = v_structs[c];
  outputFile.write( (char *) &record, sizeof(klantenbestand));
}

alleen zoals je ziet word hier 'sizeof(klantenBestand)' gebruikt.. en als ik dit dus in een functie zet, krijg ik de (logische) foutmelding dat ie niet weet wat 'klantenbestand' is.

nu lijkt het mij logisch dat wanneer ik dus een vector weg wil schrijven, ik ook de struct (of iig de layout van de stuct, het type dus) meegeef aan de functie.

alleen hoe geef ik dynamisch een type mee aan een functie? ik wil niet standaard in mijn mooie dynamische 'outputBinaryFile' bestand, alle structs declaraties gaan includen die ik van plan ben te gaan gebruiken...

is er een manier hoe ik OF een 3de argument mee kan geven aan de functie, zodat ik wel sizeof('iets') zou kunnen gebruiken??

of is er een andere manier waarop ik dyamisch een vector kan wegschrijven?

This message was sent on 100% recyclable electrons.


  • B-Man
  • Registratie: Februari 2000
  • Niet online
Het is al laat, dus misschien vergis ik me: maar als je pointers in je struct hebt staan, zou dit toch al niet werken.

Is het sowieso niet handiger om ofwel van je struct een class te maken en deze een functie te geven writeFromBinaryFile() en readFromBinaryFile() (tweede kan static zijn), zodat je alle logica mbt je klantenbestand in een class samenneemt?

Misschien dat het nog simpeler is, maar het lijkt me dat je daar al aan had gedacht: waarom zet je de definitie van 'klantenbestand' niet gewoon bij de definitie van v_structs? Dan zou je functie het type namelijk gewoon 'begrijpen'.

Verwijderd

BasieP schreef op 30 oktober 2004 @ 00:16:
nu lijkt het mij logisch dat wanneer ik dus een vector weg wil schrijven, ik ook de struct (of iig de layout van de stuct, het type dus) meegeef aan de functie.

alleen hoe geef ik dynamisch een type mee aan een functie? ik wil niet standaard in mijn mooie dynamische 'outputBinaryFile' bestand, alle structs declaraties gaan includen die ik van plan ben te gaan gebruiken...

is er een manier hoe ik OF een 3de argument mee kan geven aan de functie, zodat ik wel sizeof('iets') zou kunnen gebruiken??

of is er een andere manier waarop ik dyamisch een vector kan wegschrijven?
Ik denk dat je probleem algemener is dan de vraag hoe je dat 'dynamisch type' zoals jij het noemt meegeeft aan die functie. Ik kan een paar dingen bedenken voor je specifiek probleem hier, maar die zijn eigenlijk allemaal even slecht.

Wat jij wil is wat men noemt persistentie van objecten. Alhoewel je daar waarschijnlijk wel RTTI (Run Time Type Identification) voor kunt gebruiken doe ik het zelf zelden of nooit, al geef ik toe dat de beste reden die ik daarvoor heb is dat ik RTTI niet goed ken. Er zijn wel een paar andere mogelijkheden. Je zou je struct of klasse kunnen voorzien van een functie die ervoor zorgt dat je een struct/klasse kunt inlezen en/of uitschrijven, zoals B-Man al aangeeft. Beter is denk ik om een 'friend operator<<' te implementeren op je object dat een algemene ostream aanneemt (en een object van je klasse/struct natuurlijk). Ik hou het bewust eenvoudig omdat ik aanneem dat je geen hele waaier aan formaten zult ondersteunen. En mocht je dat alsnog willen, dan kun je nog altijd een kleine uitbreiding doen ;)
Omdat je blijkbaar hele vectoren wil gaan wegschrijven, kun je een daar ook wel een kleine functie voor schrijven in het licht van wat ik net zei. De enige beperking die je dan oplegt aan de objecten die je in zo'n vector wil gooien is dat ze zichzelf kunnen uitschrijven/inlezen, maar dat is toch je bedoeling hier, dus dat lijkt me niet echt een beperking. Het enige potentiele probleem wat je met zo'n oplossing hebt is dat je precies moet weten wat je gaat inlezen (want ik neem aan dat dat de volgende stap zal worden). Maar ook daar zijn wel een paar dingen te bedenken...Anyway, als ik even snel wat code intyp voor wat ik net zeg, dan kom ik op iets in deze aard (waarschuwing: GEEN error checking voor de duidelijkheid van m'n code, dus ga aub checken op falende input enzo meer):
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;

class Klant
{
public:

    Klant( string inName )
    : mName( inName )
    {};

    friend ostream& operator<<( ostream& os, const Klant& inKlant );
    friend istream& operator>>( istream& is, Klant& outKlant );

private:
    string mName;
};


ostream& operator<<( ostream& os, const Klant& inKlant )
{
    os << "Klant " << inKlant.mName.c_str();
    return os;
}

istream& operator>>( istream& is, Klant& outKlant )
{
    string theKlant;
    is >> theKlant;
    string theName;
    is >> theName;
    outKlant = Klant( theName );
    return is;
}

template<class T>
ostream& operator<<( ostream& os, const vector<T>& inVector )
{
    os << "Size " << inVector.size() << endl;
    for ( int i = 0; i < inVector.size(); ++i )
    {
        os << inVector[i] << endl;
    }
    return os;
}

template<class T>
istream& operator>>( istream& is, vector<T>& outVector )
{
    outVector.clear();

    string theString;
    is >> theString;

    int theSize = 0;
    is >> theSize;
    
    for ( int i = 0; i < theSize; ++i )
    {
        Klant klant( "" );
        is >> klant;
        outVector.push_back( klant );
    }
    return is;
}


int main( int argc, char* argv[] )
{
    vector<Klant> Klanten1;
    vector<Klant> Klanten2;

    // Klanten1 opvullen
    Klanten1.push_back( Klant( "BasieP" ) );
    Klanten1.push_back( Klant( "_piranha_" ) );

    // even op het scherm tonen
    cout << "Klanten1:" << endl << Klanten1 << endl;

    // Klanten1 naar bestand schrijven
    fstream theOutputFile( "klanten.dat", ios::out );
    theOutputFile << Klanten1;
    theOutputFile.close();

    // Klanten2 inlezen van het bestand
    fstream theInputFile( "klanten.dat", ios::in );
    theInputFile >> Klanten2;
    theInputFile.close();

    // en even op het scherm tonen
    cout << "Klanten2: " << endl << Klanten2;

    return 0;
}

Bemerk trouwens dat ik met hetzelfde gemak een vector van Klanten naar het scherm uitschrijf als naar een file.
Ik kan verder tientallen dingen bedenken ivm deze code die anders en/of beter kunnen. Om te beginnen alvast die mottige Klant("") lijn omdat ik geen default constructor heb geschreven enzo. Maar het was dan ook enkel de bedoeling om m'n voorstel wat te illustreren met wat code en niet om een C++ schoonheidswedstrijd (zowel qua stijl als qua design) te houden :P Anyway, het is een mogelijkheid denk ik, die je eens kunt bekijken.

Trouwens, je zou ook eens naar de STL algorithms kunnen kijken (for_each, copy misschien), da's altijd interessant om weten. Kun je soms van die mottige for loops mee vermijden en die functionaliteit mooi wegsteken in een klasse/struct ;)

B-Man: ik weet niet of je 't weet, maar je moet van een struct geen klasse maken om er een functie bij te trekken hoor. Je kunt er zelfs constructor enzo opzetten. Ik weet zeker dat een stukje code als
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct test
{
    int mI;

    test( int i )
    : mI( i ) 
    {};

    void operator() ()
    {
        cout << mI << endl;
    };
};

int main( int argc, char* argv[] )
{
    struct test theTest( 5);
    theTest();
    return 0;
}

5 zal uitschrijven :) Dus ik denk dat het enige verschil tussen een struct en een klasse de access permissies is. Een struct is als het ware een klasse met alles public. En er is vast wel een expert hier die dat kan bevestigen/ontkennen ;)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Een struct is als het ware een class met default public:, totdat je private: of protected: gebruikt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 19-10-2025
oke.. ik heb even alles gelezen, en de conclusie die ik trek is dat het dus niet mogelijk is om een functie te maken die een vector wegschrijft die verschillende structs kan hebben.

misschien was ik in de TS niet echt duidelijk over wat ik nou bedoelde, maar het is dus de bedoeling dat die functie, een vector wegschrijft ZONDER dat ik de struct hoef te declareren (dus dat ik hem meegeef aan de functie)

ik wil dus in me functie dit NIET hebben:
C++:
1
2
3
4
5
6
7
8
struct klantenBestand {

..

};

vector<klantenBestand> v_structs;
klantenBestand record;

maar omdat ik bij een vector moet aangeven welk type (struct) er in zit (op regel 7), is dit dus niet mogelijk


wat dus resulteerd in een functie die er bijv zo uitziet:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <klantenbestand>
#include <anderestruct>
#include <etc>

bool outputBinaryFile(char fileName[],vector<?????????> v_structs) {
  ?????????? record;
  ofstream outputFile;

  outputFile.open(fileName, ios::binary);
  if (outputFile.fail())
    return false;

  for (int c=0; c<v_structs.size(); c++) {
    record = v_structs[c];
    outputFile.write( (char *) &record, sizeof(??????????));
  }
  
  outputFile.close();
  return true;
}

in dit bestand zit dus tussen de includes ook de delaraties van een aantal structs

maarrrrr dan weer de vraag wat ik op de vraagtekens in moet vullen? want normaal komen daar de namen van de typen structs te staan (dus 'klantenBestand' uit het vorige voorbeeld)
maar dit wil ik er niet static in hebben :|

[ Voor 40% gewijzigd door BasieP op 30-10-2004 10:41 ]

This message was sent on 100% recyclable electrons.


Verwijderd

Dan moet je er een template van maken:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename structType>
bool outputBinaryFile(char fileName[],vector<structType> v_structs) {
  structType record;
  ofstream outputFile;

  outputFile.open(fileName, ios::binary);
  if (outputFile.fail())
    return false;

  for (int c=0; c<v_structs.size(); c++) {
    record = v_structs[c];
    outputFile.write( (char *) &record, sizeof(structType));
  }
  
  outputFile.close();
  return true;
}

  • Domokoen
  • Registratie: Januari 2003
  • Laatst online: 20-05 14:26
Oerman heeft gelijk, dit is de manier waarop het kán werken.
Maar dit stort in elkaar als je pointers of class instances in je struct hebt zitten (ik denk bijvoorbeeld aan strings). Wat zit er precies in allemaal?
Pagina: 1