[C++] Callback-functie dmv pointers

Pagina: 1
Acties:

  • Invisible_man
  • Registratie: Juni 2006
  • Laatst online: 17-11 19:01
Ik ben redelijk nieuw met het programmeren in C++ (ben meer een C# programmeur) en ben nu al enige tijd bezig om een redelijk eenvoudig probleem op te lossen. Als eerst een omschrijving van wat ik wil bereiken:

Ik heb twee klassen, de "hoofdklasse" (noem ik voor het gemak A) is een klasse die de form-afhandeling doet. Op dit form zit een soort agenda/rooster waarmee een planning gemaakt kan worden. Hier voor is een tweede klasse, die ik B noem.

B is dus een onderdeel van A, oftewel A kan van alles met B doen, maar B kan dat niet met A. Nu heb ik een event in B (als er op een vakje in het rooster geklikt wordt) waarin ik de geselecteerde naam in een combobox wil veranderen, alleen zit deze combobox niet in B, maar in A.

Nu heb ik zelf natuurlijk al het één en ander geprobeerd en ben via Google terecht gekomen op "function pointers". Ook weet ik omdat ik met klassen werk ook dat ik de pointer naar de desbetreffende klasse moet hebben (de "this" van A bij wijze van spreke). Hierbij heb ik deze tutorial gevolgd. Alleen zit ik nu nog met het probleem hoe ik de static functie in A kan aanroepen vanuit B (ik heb het wel al voor elkaar om de this pointer van A in B op te slaan).

Concreet heb ik nu twee vragen:
Vraag1: Hoe kan ik vanuit B een static functie van A aanroepen?

Vraag2: Is er een betere manier om een dergelijke callback functie te realiseren?

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Voor static functies heb je natuurlijk geen A pointer nodig - de functie is immers static, en werkt dus niet op een instance.

Kun je aangeven wat je al geprobeerd hebt, want ik snap niet waar je nu moeite mee hebt. Is het gewoon een kwestie van even de syntax weten? Die kun je natuurlijk ook wel in de documentatie of verscheidene tutorials lezen:
C++:
1
2
3
4
void B::eenFunctie()
{
    A::eenAndereFunctie();
}


Of heb je last van het circular dependency probleem, waarbij je A niet vanuit B kunt includen omdat A B al include? Het had handig geweest als je dan de exacte compile errors hier had neergezet.

Over vraag 2, ik ben zelf wel een fan van std::tr1::function / boost::function, maar het kan natuurlijk ook middels interfaces.

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.


  • Invisible_man
  • Registratie: Juni 2006
  • Laatst online: 17-11 19:01
.oisyn schreef op dinsdag 02 september 2008 @ 10:56:
Voor static functies heb je natuurlijk geen A pointer nodig - de functie is immers static, en werkt dus niet op een instance.

Kun je aangeven wat je al geprobeerd hebt, want ik snap niet waar je nu moeite mee hebt. Is het gewoon een kwestie van even de syntax weten? Die kun je natuurlijk ook wel in de documentatie of verscheidene tutorials lezen:
C++:
1
2
3
4
void B::eenFunctie()
{
    A::eenAndereFunctie();
}


Of heb je last van het circular dependency probleem, waarbij je A niet vanuit B kunt includen omdat A B al include? Het had handig geweest als je dan de exacte compile errors hier had neergezet.

Over vraag 2, ik ben zelf wel een fan van std::tr1::function / boost::function, maar het kan natuurlijk ook middels interfaces.
Het komt meer neer op het tweede, maar ben al bezig even een voorbeeld stukje code te schrijven die het probleem hopelijk wat duidelijker maakt.

Edit: Als belooft:
C++: A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//////A.h//////
class A : public CFormView
{
    //Form Data
    public:
        CComboBox cbox;
    
    //Operations
    public:
        static void SetCombobox(void* ptr2Object, CString cmboxtext);
}

//////A.cpp//////
#include "A.h"
#include "B.h"

void A::SetCombobox(void* ptr2Object, CString cmboxtext)
{
    A* myzelf = (A*)ptr2Object;
    myself->cbox.SelectString(0, cmboxtext);
}

En
C++: B
1
2
3
4
5
6
7
8
9
10
11
12
//////B.h//////
class B
{
    void* ptrToInstanceOfA;
}

//////B.cpp//////
void B::OnLButtonDown()
{
    //Hier wil ik dus de static functie SetCombobox aan roepen van A
    SetCombobox(ptrToInstanceOfA, "éénofanderestring");
}


Met bovenstaande code komt hij dan met de error dat "SetCombobox" een undeclared indentifier is.
Oftewel, hoe kan ik die static functie aanroepen?

[ Voor 29% gewijzigd door Invisible_man op 02-09-2008 11:09 ]


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat je jezelf af moet vragen is wanneer je een definitie van een klasse daadwerkelijk nodig hebt. Om een pointer naar iets te declareren heb je namelijk helemaal geen definitie nodig - de compiler hoeft alleen maar te weten dat het type bestaat, niet hoe het eruit ziet, om ernaar te kunnen wijzen. Natuurlijk heb je die definitie wel nodig op het moment dat je bijv. een method aan gaat roepen op het object waar de pointer naar wijst.

Classes en structs kun je declareren dmv
C++:
1
2
class MyClass;
struct MyStruct;

Hiermee zeg je tegen de compiler dat MyClass en MyStruct bestaan, maar niet hoe ze eruit zien. Vervolgens kun je ze gebruiken om er pointers en references mee te definieren, of functie-argumenten of -returnwaarden mee te definieren.

Feitelijk hoef je een header van een klasse (B) alleen maar vanuit een andere header (A) te includen als je in A een klasse hebt met B als member (en dus geen pointer-naar-B, maar echt gewoon een B), of members van B nodig hebt (nested types, constanten, variabelen, functies)

.edit nav je codevoorbeeld:
Kijk nog eens naar mijn eerste post. En waarom definieer je die pointers als void*?

[ Voor 5% gewijzigd door .oisyn op 02-09-2008 11:13 ]

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.


  • Invisible_man
  • Registratie: Juni 2006
  • Laatst online: 17-11 19:01
[b][message=30671636,noline]En waarom definieer je die pointers als void*?
Dit wordt ook zo gedaan in het voorbeeld dat ik gevolgd heb, heeft er dacht ik mee te maken dat je zo een pointer hebt naar een verder onbekend object.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Met bovenstaande code komt hij dan met de error dat "SetCombobox" een undeclared indentifier is.
Oftewel, hoe kan ik die static functie aanroepen?
A::SetCombobox(ptrToInstanceOfA, "éénofanderestring");

?

Maar als je toch een pointer naar A hebt, dan kan je toch ook gewoon member functies aanroepen? i.e. aptr->setCombobox()

[ Voor 21% gewijzigd door Zoijar op 02-09-2008 11:27 ]


  • Invisible_man
  • Registratie: Juni 2006
  • Laatst online: 17-11 19:01
Zoijar schreef op dinsdag 02 september 2008 @ 11:25:
[...]

A::SetCombobox(ptrToInstanceOfA, "éénofanderestring");

?
Met ik wel eerst A kennen, en deze ken ik niet in B (heb overigens wel een pointer naar de instantie van A in B ).

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waarom include je A.h dan niet vanuit B.cpp?

[ Voor 7% gewijzigd door .oisyn op 02-09-2008 11:32 ]

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

b.h laten beginnen met #include "a.h", lijkt me geen probleem hier.

Maar je hebt de member functie opnieuw uitgevonden: een statische functie die een pointer naar de instance meekrijgt, i.e. "this".

  • Invisible_man
  • Registratie: Juni 2006
  • Laatst online: 17-11 19:01
.oisyn schreef op dinsdag 02 september 2008 @ 11:31:
Waarom include je A.h dan niet vanuit B.cpp?
Omdat ik dan het circular dependency probleem waar .oisyn het al over had krijg, A include B al, dan kan je niet B weer in A includen (of heb ik het nou mis). Als ik dit overigens gewoon probeer komt hij met diverse syntax errors zoals "missing ':' before indentifier 'B' op alle plekken waar iets van B wordt aangeroepen.

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

.oisyn in "\[C++] Callback-functie dmv pointers"

Maar goed, omdat we je blijkbaar aan het handje moeten nemen, hier de oplossing:
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
// A.h
class B;  // forward declaration naar B

class A
{
public:
    A();
    void EenFunctie(int bla);
private:
    B * bPtr;
};

// A.cpp
#include "A.h"
#include "B.h"

A::A()
{
    bPtr = new B(this);
}

void EenFunctie()
{
    // doe iets
}


// B.h
class A;

class B
{
public:
    B(A*);
    void NogEenFunctie();
private:
    A * aPtr;
}

// B.cpp
#include "B.h"
#include "A.h"

B::B(A * a)
{
    aPtr = a;
}

void B::NogEenFunctie()
{
    aPtr->EenFunctie();
}

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Waarschijnlijk kan je gewoon zo iets doen:

C++:
1
2
3
4
5
6
7
8
9
10
class B; // forward declaration
class A {
// declarations
};
class B {
// declarations
};

A::xxx // definitions
B::xxx // definitions

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Slecht idee. Class B weet nu teveel van A af, en is daardoor niet herbruikbaar. Class B moet een signal zenden. Class A zal een slot hebben, en bij het aanmaken van object B zal object A zijn eigen slot met het signal van B verbinden. Daardoor weet B niets meer van A af, en is je circular dependency gebroken.

Google eens op MVC, Model-View-Controller. Dit soort problemen zijn niet nieuw, er zijn goede bestaande patterns.

[ Voor 20% gewijzigd door MSalters op 02-09-2008 14:56 . Reden: MVC tip in het midden van een specifieke oplossing was idd verwarrend ]

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


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Dat klinkt meer als dependency injection dan als MVC (hoewel de twee elkaar natuurlijk niet uitsluiten)?

[ Voor 32% gewijzigd door Confusion op 02-09-2008 13:05 ]

Wie trösten wir uns, die Mörder aller Mörder?


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
All problems in computer science can be solved by another level of indirection ( ...except for the problem of too many layers of indirection. )
Wikipedia: Abstraction layer

[ Voor 14% gewijzigd door farlane op 02-09-2008 13:52 ]

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.


  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 23:50
MSalters schreef op dinsdag 02 september 2008 @ 12:40:
Slecht idee. Class B weet nu teveel van A af, en is daardoor niet herbruikbaar. Class B moet een signal zenden. Class A zal een slot hebben, en bij het aanmaken van object B zal object A zijn eigen slot met het signal van B verbinden. Daardoor weet B niets meer van A af, en is je circular dependency gebroken.

Google eens op MVC, Model-View-Controller. Dit soort problemen zijn niet nieuw, er zijn goede bestaande patterns.
Alleen een slecht idee als je herbruik voor ogen hebt, maar dit staat in 'Programming'.
Het is een goede tip in de Rubriek Software Engineering & Architecture ;)
Google dan ook eens op delegates.

In aanvulling: ben je tevreden met quick & dirty, dan zouden de tips je genoeg moeten helpen, wordt je klus nog veel moeilijker, en/of wil je verder in de Software branche, dan ga op zoek naar die MVC en vele andere design patterns.
Redesign voor het te laat is.. Of ga refactoren.
Pagina: 1