[C++ G++/GCC] Compilen van naar elkaar includende bestanden

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • vdvleon
  • Registratie: Januari 2008
  • Laatst online: 08-06-2023
Hallo iedereen,

Ik loop eigenlijk heel vaak tegen dit probleem op.
Ik heb in dit geval 2 classess:
- XMLReader
- XMLReaderChild

Deze verwijzen naar elkaar:

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
/// XMLReader.hpp
#ifndef _XMLReader_HPP_
#define _XMLReader_HPP_

...

#include "XMLReaderChild.hpp"

class XMLReader{
    private:
        // Vars
        XMLReaderChild root;
        
        ...
};

#endif

/// XMLReaderChild.hpp
#ifndef _XMLReaderChild_HPP_
#define _XMLReaderChild_HPP_

...

#include "XMLReader.hpp"

class XMLReaderChild{
    ...
    
    friend void XMLReader::readAttributes(XMLReaderChild& child, xmlAttrPtr attribute);
    friend void XMLReader::readChildren(XMLReaderChild& parent, xmlNodePtr children);
};

#endif


Maar als je dan de body van XMLReader (XMLReader.cpp) cimpiled krijg je allemaal meldingen zoals:
XMLReaderChild.hpp:131: fout: 'XMLReader' has not been declared (dit slaat op de friend regels)
etc.

Hoe moet je nou je files indelen (ofsow) zodat hij wel alles goed compiled? Het is vast iets heel simpels, maar dit gaat zo'n beetje altijd fout zodra bestanden naar elkaar verwijzen :S

Bedankt voor je hulp alvast

Acties:
  • 0 Henk 'm!

  • coubertin119
  • Registratie: Augustus 2002
  • Laatst online: 15-09 17:06
Als je met dynamische allocatie werkt moet de grootte van een object dat je wenst te alloceren niet op voorhand bekend zijn. Aangezien de grootte van een object pas bekend is na een volledig zichtbare klassedeclaratie en je niet kan geven, is dat de gemakkelijkste manier om te werken. Dan is immers enkel de naam al genoeg.

Skat! Skat! Skat!


Acties:
  • 0 Henk 'm!

  • Forsith
  • Registratie: September 2008
  • Laatst online: 07-08-2020
Misschien praat ik nu onzin, maar is het misschien handig om beide classes bij voorhand te declareren?
Dus in XMLReader.hpp zet je dan, na je guards, "class XMLReaderChild" en vice versa.

Acties:
  • 0 Henk 'm!

  • Dricus
  • Registratie: Februari 2002
  • Laatst online: 21-09 13:26

Dricus

ils sont fous, ces tweakers

Ik weet niet of het in dit specifieke geval gaat werken, maar normaliter zou ik zoiets oplossen met een forward declaratie. Concreet kun je in dit geval de classdeclaratie van XMLReaderChild laten voorafgaan door:
C++:
1
2
// Forward declaratie
class XMLReader;


Edit:
Wat zeker gaat werken is als je XMLReaderChild forward declared in XMLReader.hpp. Je hoeft dan in dat bestand XMLReaderChild.hpp ook niet meer te includen.

[ Voor 23% gewijzigd door Dricus op 09-09-2009 19:27 ]

Stel niet uit tot morgen wat je vandaag nog tot morgen kunt uitstellen...


Acties:
  • 0 Henk 'm!

  • Forsith
  • Registratie: September 2008
  • Laatst online: 07-08-2020
Dricus schreef op woensdag 09 september 2009 @ 19:25:
Ik weet niet of het in dit specifieke geval gaat werken, maar normaliter zou ik zoiets oplossen met een forward declaratie. Concreet kun je in dit geval de classdeclaratie van XMLReaderChild laten voorafgaan door:
C++:
1
2
// Forward declaratie
class XMLReader;


Edit:
Wat zeker gaat werken is als je XMLReaderChild forward declared in XMLReader.hpp. Je hoeft dan in dat bestand XMLReaderChild.hpp ook niet meer te includen.
Ik was eerder, jij legt het beter uit (kon even niet op de naam Forward decl komen 8)7 )

Acties:
  • 0 Henk 'm!

  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

Is een forward declaratie hier van de classname alleen wel afdoende? Ik bedoel, hij specificeert ook een member als friend. Volgens mij moet je hier een forward declaratie hebben van de class XMLReader __en__ z'n members voor de friends.

Wat TS misschien ook wil overwegen is om XMLReaderChild (uitgaande ervan dat deze een reader voor een child node moet vertegenwoordigen), om deze als innerclass de declareren van XMLReader. Niet alleen omdat het vanuit een hierarchie misschien meer logisch is, maar als ik me ook goed herinner worden inner classes hier bij de meeste compilers (of alle) multi-pass gecompiled. Staat me zoiets bij iig, en zou forward declarations onnodig moeten maken. Pin me er niet op vast though ;-)

[ Voor 6% gewijzigd door prototype op 09-09-2009 19:33 ]


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22:43
Ik zie ook niet zo 1-2-3 hoe je dit precies goed kunt krijgen, want je hebt de definitie van XMLReader nodig om de friend methods in XMLReaderChild te declareren, en je hebt de definitie van XMLReaderChild nodig om XMLReader. Een cyclic dependency dus, en voor zover ik weet kun je classes en methods niet forward declareren, dus zie ik geen perfecte oplossing.

Het makkelijkste is waarschijnlijk om heel XMLReader als friend class declararen (door friend class XMLReader toe te voegen in XMLReaderChild); daarvoor is het niet nodig dat de definitie van XMLReader bekend is. Dan is minder restrictief dan je huidige code, maar beter de methoden in kwestie helemaal public te maken.

edit:
@bovenstaanden: een forward declaratie van de class volstaat niet als je aan z'n members wil refereren.

[ Voor 7% gewijzigd door Soultaker op 09-09-2009 19:35 ]


Acties:
  • 0 Henk 'm!

  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

Soultaker schreef op woensdag 09 september 2009 @ 19:33:
edit:
@bovenstaanden: een forward declaratie van de class volstaat niet als je aan z'n members wil refereren.
Dat zeg ik, gamma ;-)

Acties:
  • 0 Henk 'm!

  • Dricus
  • Registratie: Februari 2002
  • Laatst online: 21-09 13:26

Dricus

ils sont fous, ces tweakers

Soultaker schreef op woensdag 09 september 2009 @ 19:33:
edit:
@bovenstaanden: een forward declaratie van de class volstaat niet als je aan z'n members wil refereren.
Mijn eerste voorstel in mijn post zal inderdaad wellicht niet werken. Zoals ik het in mijn edit beschrijf werkt het denk ik wel. In de class XMLReader wordt namelijk (zo te zien) niet gerefereerd naar members van XMLReaderChild.

Stel niet uit tot morgen wat je vandaag nog tot morgen kunt uitstellen...


Acties:
  • 0 Henk 'm!

  • vdvleon
  • Registratie: Januari 2008
  • Laatst online: 08-06-2023
Ik heb het opgelost:

Voor de XMLReaderChild zet ik idd de forward decleratie: class XMLReader; en include dus niet XMLReader.hpp. Ook heb ik friend XMLReader:: ... etc. vervangen voor friend class XMLReader. Dan gaat wel alles goed. Bedankt voor de hulp in ieder geval.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22:43
Dricus schreef op woensdag 09 september 2009 @ 19:42:
Zoals ik het in mijn edit beschrijf werkt het denk ik wel. In de class XMLReader wordt namelijk (zo te zien) niet gerefereerd naar members van XMLReaderChild.
Nee, dat werkt niet, want er wordt een instantie van XMLReaderChild gedeclareerd als member variable. Dan is een definitie ook gewoon noodzakelijk.

Acties:
  • 0 Henk 'm!

  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

Had net even mijn suggestie getest met innerclasses, maar dat lijkt toch niet te werken. Volgens mij dacht ik dat dit zou werken omdat ik dacht dat de inner/nested class als een member gezien zou worden, net als dat methods en ivars members zijn van de class en deze bij intern gebruik ook geen forward declaraties behoeven. Soultaker's oplossing mbt de hele class befrienden en deze forward declareren lijkt dan idd een goede oplossing hiervoor.

Acties:
  • 0 Henk 'm!

  • vdvleon
  • Registratie: Januari 2008
  • Laatst online: 08-06-2023
Mijn XMLReader maakt dus gebruik van libxml2.

Mijn class werkt nu als volgt (in een voorbeeldje word dit weer gegeven):

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<persons>
    <person>
        <name>Jan</name>
        <age>23</age>
        <html><![CDATA[<a href="hoi">test</a>]]></html>
    </person>
    <person>
        <name>Henk</name>
        <age>54</age>
        <html><![CDATA[<a href="http://www.google.com/"><b>klik</b></a>]]></html>
    </person>
</persons>


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Open and get root
XMLReader xmlReader("file.xml"); // of geen argument, open dan met functie open: xmlReader.open("file.xml");
if(!xmlReader){
    // fout afhandeling
}
XMLReaderChild root = xmlReader.getRoot();

try{
    XMLReaderChildren childs = root.getChildren("person");
    XMLReaderChildren::iterator cit;

    for(cit=childs.begin(); cit!=childs.end(); cit++){
        std::cout << "Found person '" << cit->getChild("name").getContent() << "'\n";
    }
}catch(XMLReaderException& e){
    std::cerr << "Child not found!\n";
}


De functie getChild(<name>) returned de eerste element met name = <name> of throw-ed een exception als niet is gevonden
De functie getChildren() returend lijst van alle childs
De functie getChildren(<name>) returned lijst van alle childs met naam = <name>
Verder heb je nog getAttributes() deze returned een string map (vector<string, string>) van alle attributes.
En getAttribute(<name>, bool* ok=NULL) geeft een attribute terug, als deze niet bestaat dan een lege string. Als de ok pointer niet null is, geeft deze ook weer of de attribute bestond of niet.

Met deze functies kan je eigenlijk van xml lezen wat je maar wilt. (wat ik wil teminste).

Ik ben er blij mee ;)

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Je kunt ook een forward declaration van je functie geven die je hier aanroept. Forward declaring houdt niet alleen op bij classes het werkt ook voor functies zoals in C.

Alle methods van een functie die niet in de header worden geimplementeerd zijn forward declarations van die methods. In de cpp schrijf je de implementatie.

[ Voor 24% gewijzigd door NC83 op 09-09-2009 20:54 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:35
Waarom moeten die functies in XMLReader eigenlijk friends zijn van XMLReaderChild ?

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.


Acties:
  • 0 Henk 'm!

  • user109731
  • Registratie: Maart 2004
  • Niet online
farlane schreef op woensdag 09 september 2009 @ 22:18:
Waarom moeten die functies in XMLReader eigenlijk friends zijn van XMLReaderChild ?
Omdat hij XMLReader::readAttributes toegang wil geven tot XMLReaderChild private members?

[ Voor 35% gewijzigd door user109731 op 09-09-2009 22:50 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

prototype schreef op woensdag 09 september 2009 @ 19:46:
Had net even mijn suggestie getest met innerclasses, maar dat lijkt toch niet te werken.
Dat zou anders gewoon moeten werken hoor. Zo althans:

C++:
1
2
3
4
5
6
7
8
9
class Aap
{
    void mies();

    class Noot
    {
        friend void Aap::mies();
    };
};

Het lukt idd niet zodra je de declaratie van void mies() onder de definitie van Noot zet :).

Overigens zou ik ook niet te strict gaan doen en gewoon de hele class friend maken. Ze zijn immers onderdeel van hetzelfde systeem, en daardoor "betrouwbaar".
NC83 schreef op woensdag 09 september 2009 @ 20:52:
Je kunt ook een forward declaration van je functie geven die je hier aanroept. Forward declaring houdt niet alleen op bij classes het werkt ook voor functies zoals in C.
Ja, alleen gebruikt hij hier member functions, en die kun je weer niet forward declaren.

[ Voor 23% gewijzigd door .oisyn op 09-09-2009 23:36 ]

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.


Acties:
  • 0 Henk 'm!

  • vdvleon
  • Registratie: Januari 2008
  • Laatst online: 08-06-2023
JanDM schreef op woensdag 09 september 2009 @ 22:46:
[...]

Omdat hij XMLReader::readAttributes toegang wil geven tot XMLReaderChild private members?
Het komt er op neer dat ik XMLReaderChild alleen met data wil kunnen vullen vanuit XMLReader maar niet vanuit de gebruiker zelf.

Dus:

XMLReaderChild child;
child.setName("test");

zou niet mogen kunnen, want het is een READER systeem, geen WRITE systeem. Vandaar.

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
.oisyn schreef op woensdag 09 september 2009 @ 23:22:
[...]

[...]

Ja, alleen gebruikt hij hier member functions, en die kun je weer niet forward declaren.
Wel als ze static zijn.

Edit nevermind volgens mij ben ik met iets anders in de war sorry :(

[ Voor 12% gewijzigd door NC83 op 09-09-2009 23:58 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

vdvleon schreef op woensdag 09 september 2009 @ 23:50:
[...]


Het komt er op neer dat ik XMLReaderChild alleen met data wil kunnen vullen vanuit XMLReader maar niet vanuit de gebruiker zelf.

Dus:

XMLReaderChild child;
child.setName("test");

zou niet mogen kunnen, want het is een READER systeem, geen WRITE systeem. Vandaar.
Maar je maakt het jezelf daarmee nogal lastig, want zodra je readChildren() wat gecompliceerder wordt en je gebruik gaat maken van helper functions die je aanroept vanuit readChildren(), dan kun je vanuit die helper functions weer niet de attributes zetten omdat die helper functions zelf immers geen friends zijn. Het is daarom handiger om sowieso de hele XMLReader class (wat je nu al doet) een friend te maken.

Overigens ben ik het niet helemaal met je designfilosofie eens. Op deze manier kun je alleen maar een XML boom constructen vanuit een XML string. Wat als je nou gewoon ergens vanuit code een XML boom wilt vullen? Dit terwijl je nooit de intentie hebt om die weg te schrijven, maar omdat je die XML boom aan een andere functie geeft die een ingelezen XML boom verwacht.

[ Voor 19% gewijzigd door .oisyn op 10-09-2009 10:54 ]

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.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:27

.oisyn

Moderator Devschuur®

Demotivational Speaker

Overigens, in het kader van vieze oplossingen :P, dit werkt wel:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// xmlreaderchild.h
template<class T> class XMLReaderChildT
{
    friend void T::readChildren();
};
typedef XMLReaderChildT<class XMLReader> XMLReaderChild;


// xmlreader.h
class XMLReader
{
public:
    void readChildren();
};

[ Voor 32% gewijzigd door .oisyn op 10-09-2009 16:08 ]

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