[C++] objectinstantie van parentform meegeven aan childform

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Ik ben bezig met het bouwen van een C++ programma met de Ultimate++ library. Ik heb een hoofdform en een form voor het maken van instellingen. Dit form kan middels een knop op het hoofdform worden geopend. Nu heb ik een class die dient voor het beheren van een aantal instelbare variabelen die opgeslagen worden in een XML file. Dit werkt allemaal prima. De instantie van deze class zit in de hoofdform, omdat de hoofdform altijd open is en er dus geen problemen komen met het vernietigen van de configuratie-class.

Nu wil ik echter de opgeslagen instellingen in de configuratie-class in de instellingenform gebruiken. Ik wil geen dubbele variabelen hebben dus ik wil een pointer naar de bestaande instantie meegeven aan de instellingenform. Dit is een goede oplossing toch? Als ik er compleet naast zit dan zeg het me!

In C# zou ik het zo doen, ik doe het al jaren en het werkt altijd:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Hoofdform : Form
{
     Configuratieclass mConf;

     InstellingenForm miForm = new InstellingenForm(mConf);
     
     void OpenInstellingen()
     {
          miForm.ShowDialog();
     }
}
class InstellingenForm : Form
{
     ConfiguratieClass mConf;

     InstellingenForm(ConfiguratieClass pConf)
     {
          mConf = pConf;
     }
}


Nu zit ik hier in C++ echter met een probleem. De forms zijn geen classes, maar structs. Echter heb ik ze veranderd in classes en mijn idee toegepast. Ik kreeg geen errors maar in de runtime kwam ik meteen een fout tegen. Naar mijn idee is het een memory leak of een corrupte pointer waar ik niet op heb gelet. De code zoals ik het in C++ heb gemaakt zag er zo uit.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
struct SettingsDialog : public TopWindow // Dit is de instellingenform die erft van de U++ library
{
     ConfigurationStorage mStor; // lokale variabele is wel nodig anders kan ik de instellingen niet meer opslaan nadat de objecten zijn ingeladen

     // meer object/functie definities...
}
SettingsDialog::SettingsDialog(ConfigurationStorage& pConfig) // Dit is de constructor van het instellingenformulier
{
     mStor = pConfig;

     // objecten uit het pConfig object worden ingeladen, dit zijn strings. Hier krijg ik dus runtime fouten. Meestal zijn het assert fail fouten.
}


Kan iemand me hiermee helpen? Ik doe nog niet zo heel lang C++ en ik ben nog steeds bezig met zo veel mogelijk te leren. Ik heb al veel problemen met pointers gehad wanneer de variabele in kwestie bijvoorbeeld al was vernietigd. Tijdens het debuggen zag ik ook dat de inhoud van een vector<string> in pConfig aangaf: "Unable to read memory". De waardes klopten ook niet. Er klopt dus iets niet in mijn pointer! Ik heb overigens ook de variabele meegegeven als: "ConfigurationStorage pConfig", en "ConfigurationStorage* pConfig". Beide geven foutmeldingen.

Acties:
  • 0 Henk 'm!

  • Waster
  • Registratie: September 2006
  • Laatst online: 14-04 17:49
Altijd lastig die pointers en referenties in C++ :)

Als ik je code voorbeeld zie dan wil je denk ik dat beide mConf in de verschillende classes naar hetzelfde object wijzen. In je C++ voorbeeld gebruik je referenties. Nou kun je referenties alleen definieren bij initialisatie. Je kunt niet eerst de variabele definieren en daarna nog de referentie zetten. Dat komt omdat bij een referentie er achter de schermen direct naar hetzelfde stukje geheugen wordt verwezen. Voor een referentie moet je dat dus direct bij initialisatie doen. Anders heeft de compiler al eigen geheugen gereserveerd. Bij class variabelen kom je nu dus in de problemen, omdat zodra de class geconstrueerd wordt is alle geheugen voor pConf gereserveerd. Dus de verschillende Confs kunnen nooit naar hetzelfde object wijzen. Daarvoor hebben we dus pointers om dit te bereiken. Referenties zijn vooral handig in functies zodat je niet het hele object hoeft gekopieerd te worden.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15:26
Als je een reference naar een object in een class wilt gebruiken, moet je 'em (itt een pointer) in de constructor initializer list initialiseren:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Settings{ int a; };

class SettingsDialog
{
    Settings& settings;

public:
    SettingsDialog( Settings& s ) : settings( s )
    {
        settings.a =0xDEADBEEF;
    }
};

int main(int argc, char* argv[])
{
    Settings settings;
    SettingsDialog dlg( settings );

    assert( settings.a == 0xDEADBEEF );
}


Dat is de enige manier waarop de compiler kan garanderen dat de reference ook daadwerkelijk aan een valide object referereert. Dit is een signicant verschil met een pointer die ook in het wilde weg mag pointen ( of naar 0 ), en die je dus ook buiten de initializer list een waarde mag geven.

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!

  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Dankjewel voor jullie reacties! Het probleem waar ik ook mee zat was dat mijn declaraties allemaal in de header file staan. Daarom kreeg ik bij het maken van een andere constructor een foutmelding van een non-suitable default constructor. Ik heb een oplossing gevonden voor mijn probleem. De code is als volgt. Kunnen jullie me vertellen of dit een goede oplossing is? Als ik dit in C# zou doen dan zou mijn docent op school me afslaan denk ik...

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// header file

static ConfigurationStorage mConf;

class SettingsDialog sealed : public TopWindow { // declaraties... }

struct MainForm : public TopWindow
{
     SettingsDialog* mSettingsDialog;
     // meer declaraties....
}

// .cpp file

MainForm::MainForm()
{
     mSettingsDialog = new SettingsDialog();
     // andere code....
}


Nu kan ik er vanuit ieder object in mijn applicatie bij. Ik ben alleen niet helemaal zeker hoe de compiler met het geheugen zal omgaan en wanneer het object vernietigt gaat worden.

Acties:
  • 0 Henk 'm!

  • Waster
  • Registratie: September 2006
  • Laatst online: 14-04 17:49
Ik wist niet dat je ook class variabelen als referentie kon maken. Weer wat geleerd :)

Wat is het bezwaar van je code? Dat je overal bij je configuratie object kan?

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15:26
evolution536 schreef op woensdag 17 oktober 2012 @ 10:23:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// header file

static ConfigurationStorage mConf;

class SettingsDialog sealed : public TopWindow { // declaraties... }

struct MainForm : public TopWindow
{
     SettingsDialog* mSettingsDialog;
     // meer declaraties....
}

// .cpp file

MainForm::MainForm()
{
     mSettingsDialog = new SettingsDialog();
     // andere code....
}


Nu kan ik er vanuit ieder object in mijn applicatie bij. Ik ben alleen niet helemaal zeker hoe de compiler met het geheugen zal omgaan en wanneer het object vernietigt gaat worden.
Die constructie is waarschijnlijk niet wat je wilt : door hem static te maken krijgt iedere 'translation unit' ( ofwel source file + includes ) die gecompileerd wordt in je project een variabele met de mConf, maar geen van de units heeft het over hetzelfde ding :)

Maw, als je iets dergelijks wilt, declareer je de variabele 'extern' in de header ( zonder toevoeging heeft een variabele default external linkage overigens ) en definieer je em eenmalig in een geschikte cpp file.

Het is aan te raden om de scope van een variabele zo klein mogelijk te houden overigens, de variabele die je nu introduceert is eigenlijk global voor je hele programma. Niet perse slecht ( en voor settings misschien wel logisch ) maar als je er veel van hebt kan het een bende worden.

Als je docent je 'afslaat' omdat je een global maakt is 'tie een smurf. Als je 'em onnodig global maakt heeft ie gelijk :)

[ Voor 15% gewijzigd door farlane op 17-10-2012 11:57 ]

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!

  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
Maw, als je iets dergelijks wilt, declareer je de variabele 'extern' in de header ( zonder toevoeging heeft een variabele default external linkage overigens ) en definieer je em eenmalig in een geschikte cpp file.
Hartstikke bedankt! Dit werkt ook prima. in de headerfile zet je:

C++:
1
extern ConfigurationSettings mConf;


En in de source file (.cpp) zet je:

C++:
1
ConfigurationSettings mConf;


Dankjewel voor jullie hulp, dit onderdeel werkt nu :)

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15:26
evolution536 schreef op woensdag 17 oktober 2012 @ 14:41:
Hartstikke bedankt! Dit werkt ook prima.
Vergeet ook vooral niet te leren wat een translation unit is, wat met linkage wordt bedoeld en wat scope inhoudt, want dat was eigenlijk mijn bedoeling.

[ Voor 6% gewijzigd door farlane op 17-10-2012 16:12 ]

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!

  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024
farlane schreef op woensdag 17 oktober 2012 @ 16:11:
[...]

Vergeet ook vooral niet te leren wat een translation unit is, wat met linkage wordt bedoeld en wat scope inhoudt, want dat was eigenlijk mijn bedoeling.
Ga ik zeker ook doen, ik had het ook uit je post gehaald :)
Pagina: 1