Toon posts:

[C++] Pointer naar member functies...

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik zit met een schoolopdracht met het volgende probleem. Ik heb een class genaamd X. Hierin zit een classmember met de naam Y.

Nu moet ik een pointer doorgeven naar een C functie. Ik moet dus een pointer zien te maken naar de classmember Y. Ik heb dit op allerlei manieren geprobeerd om dit voor elkaar te krijgen maar ik kan de juiste cast niet te voorschijn toveren.

Als iemand me hier mee kan helpen zou ik hem eeuwig dankbaar zijn.

Ik heb uiteraard ook nog een stukje code als voorbeeld ;)

De header van functie GeefFunctiePtrDoor is:
void GeefFunctiePtrDoor ( void (__cdecl *)(void) );

Dit is een gegeven methode en mag niet veranderd worden.

code:
1
2
3
4
5
6
7
8
9
class X
{
public:
   void Y(void) { // .. body van deze methode is niet interessant }
};

X *a = new X();   // Dit moet zo blijven (dynamische allocering)

GeefFunctiePtrDoor ( // .. hier moet m'n pointer naar Y dus worden aangemaakt.. maar hoe? :P );


Wie o wie kan mij de juiste cast geven :>

- ThaFreak

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Een member functie ziet er intern anders uit dan een gewone C functie. Er wordt namelijk een 'this' pointer meegegeven, die wijst naar het object waarop de member wordt aangeroepen.

Je kan dus geen member functie pointer doorgeven als 'gewone' C functie pointer. Wat je wel kan doen is een tweede globale C functie maken, die vervolgens de member op het object aanroept.

Dus iets van:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
X* theObj;

void thunk() {
   theObj->Y();
}

void geefFunctiePtrDoor(void (*funcptr)()) {
   funcptr();
}

X* a = new X();

theObj = a;
GeefFunctiePtrDoor(thunk);


(Je kan het meer "fancy" doen, met class static functies oid, maar het basis idee blijft hetzelfde)

[ Voor 19% gewijzigd door Zoijar op 07-10-2004 22:42 ]


Verwijderd

Maak de functie die je wilt doorgeven static, anders is het niet mogelijk.

  • Surehand
  • Registratie: Februari 2003
  • Laatst online: 14-05 21:53
In de c++ faq kun je hier ook nog wat over vinden...

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 08 oktober 2004 @ 09:26:
Maak de functie die je wilt doorgeven static, anders is het niet mogelijk.
Nutteloze oplossing dus, je kunt een instance method niet 'zomaar' static maken zonder de code te breken.

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.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

.oisyn schreef op 08 oktober 2004 @ 10:34:
[...]

Nutteloze oplossing dus, je kunt een instance method niet 'zomaar' static maken zonder de code te breken.
Dat hangt van de code af ;) Ik heb vaak genoeg instance methods gezien die het object feitelijk niet gebruikten :)

In de meeste gevallen zal je echter inderdaad met een losse static willen werken die een context-pointer terugcast naar de class instance.

Professionele website nodig?


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

.oisyn

Moderator Devschuur®

Demotivational Speaker

curry684 schreef op 08 oktober 2004 @ 12:11:
[...]

Dat hangt van de code af ;) Ik heb vaak genoeg instance methods gezien die het object feitelijk niet gebruikten :)
Sorry, ik werk niet met achterlijke collega's ;)

.edit: @ _piranha_ hieronder:
Ik noem curry dan ook niet achterlijk (want dat is ie zeker niet), ik zeg slechts dat ik er vanuit ga dat als een member niet static is dat ie dan ook niet static hoort te zijn, en dat je 'm dus ook niet zomaar static kunt maken. Maw, ik ga uit van een degelijk ontworpen programma, en niet van een stukje prutswerk ;)
(Ik bedoelde collega's dan ook meer als mijn echte collega's hier op het werk, en niet collega-moderators :))

[ Voor 52% gewijzigd door .oisyn op 08-10-2004 14:35 ]

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.


Verwijderd

.oisyn schreef op 08 oktober 2004 @ 12:18:
Sorry, ik werk niet met achtelijke collega's ;)
Hij heeft zo'n dingen gezien; hij beweerde niet dat hij ze ook zelf schreef... dus heel misschien is ie toch niet achterlijk? :+

Verwijderd

.oisyn schreef op 08 oktober 2004 @ 10:34:
[...]


Nutteloze oplossing dus, je kunt een instance method niet 'zomaar' static maken zonder de code te breken.
hoezo nutteloos? Hij vraagt toch hoe je een functie van een class door kan geven. Dit kan niet anders dan hem static te maken. Dat het zijn code breekt.. duh.. maar dat staat los van zijn vraagstelling.
Over nutteloze opmerkingen gesproken :z

[ Voor 7% gewijzigd door Verwijderd op 08-10-2004 22:26 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Verwijderd schreef op 08 oktober 2004 @ 22:25:
hoezo nutteloos? Hij vraagt toch hoe je een functie van een class door kan geven. Dit kan niet anders dan hem static te maken. Dat het zijn code breekt.. duh.. maar dat staat los van zijn vraagstelling.
Over nutteloze opmerkingen gesproken :z
Het kan wel anders hoor; je kan eerst je stack bijwerken met een asm directive en dan je pointer force casten via een union...of je space shuttle dan ook nog landen kan is de vraag, maar het kan wel.
Verder vind ik het sowieso een beetje nutteloze discussie...we weten allemaal genoeg van het onderwerp af lijkt me. Tot nu toe was mijn opmerking nog de meest zinvolle :P

Veel programmeurs etc. doen dat, elkaar pakken op kleine dingetjes. Ik denk dat dat is omdat we aangeleerd worden extreem kritisch te denken. Op mijn universiteit in ieder geval wel, als je de achterliggende gedachte achter opgaven door krijgt. Maar het is ook wel goed om op sommige momenten in te zien dat het geen nut heeft. Zelf ben ik al over kritisch, en probeer het de laatste tijd iets terug te draaien. Het is niet goed om overal zo op in te haken...

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 08 oktober 2004 @ 22:25:
[...]

hoezo nutteloos? Hij vraagt toch hoe je een functie van een class door kan geven. Dit kan niet anders dan hem static te maken. Dat het zijn code breekt.. duh.. maar dat staat los van zijn vraagstelling.
Dan heeft ie toch geen toegang meer tot de instantie waar de functie op aangeroepen moet worden? Dus nogmaals, wat heeft ie aan een dergelijke oplossing?

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: 23:07
Zoijar schreef op 09 oktober 2004 @ 02:31:
Verder vind ik het sowieso een beetje nutteloze discussie...we weten allemaal genoeg van het onderwerp af lijkt me. [..]
Veel programmeurs etc. doen dat, elkaar pakken op kleine dingetjes. Ik denk dat dat is omdat we aangeleerd worden extreem kritisch te denken. [..] Maar het is ook wel goed om op sommige momenten in te zien dat het geen nut heeft.
Niet zo relevant voor de inhoudelijke discussie, maar hier ben ik het helemaal mee eens! (Ik moet mezelf trouwens ook inhouden om niet over elk detail te struikelen.)

Wel on-topic, wil ik er nog even op wijzen dat het vrij gebruikelijk is dat zo'n callback-functie een void*-argument heeft die je kan gebruiken om de this-pointer door te geven; de functie code wordt dan zoiets:
C++:
1
2
3
4
void thunk(void *arg)
{
    reinterpret_cast<ClassX*>(arg)->methodFoo();
}

Bij de registratie geef je dan een pointer naar het object ('this' binnen een member function) door als argument.

  • Total-Control
  • Registratie: September 2000
  • Laatst online: 03-06-2025
Jip, gehele object doorgeven is het eenvoudigst.

Je functie wordt dan zoiets als:

void GeefFunctiePtrDoor(void *ptrPointerToInstance)
{
X *ptrMyPointerToInstance = (X *)ptrPointerToInstance;

... Nu kan je met ptrMyPointerToInstance aan de slag.
bv. ptrMyPointerToInstance->Y();
}

De GeefFunctiePtrDoor roep je dan aan als volgt:

GeefFunctiePtrDoor(a);

Dit vind ik zelf echter niet altijd de meest mooie oplossing; wel het eenvoudigst.

Wil je een oplossing die ook werkt bij verschillende classes gebruik dan functors.
Ik zou je graag een voorbeeld willen geven, maar heb alleen closed-source voor handen. Gelukkig is er genoeg over te vinden.

Succes!

Getting it hot makes it work, keeping it cold makes sure it stays that way.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

void GeefFunctiePtrDoor ( void (__cdecl *)(void) );

Dit is een gegeven methode en mag niet veranderd worden.
:)

Verwijderd

.oisyn schreef op 08 oktober 2004 @ 10:34:
[...]


Nutteloze oplossing dus, je kunt een instance method niet 'zomaar' static maken zonder de code te breken.
De functie die "erin gehangen" moet worden lijkt mij persoonlijk geen instance method. Maar de relatie tussen de externe functie en class of object is dan ook niet omschreven in de opdracht. De aanpak "verschillende functie per object" verschilt van de aanpak "1 functie per class". Beide methodes zijn inmiddels langsgekomen,
ThaFreak007 kan nu kiezen ;).

Verwijderd

Topicstarter
Ik heb gekozen, heb maar een simpele stub functie geschreven. Ik vroeg me alleen ff af of het uberhaupt mogelijk was maar, zoals ik al verw8 had, is het dus niet mogelijk zo als ik het graag gewenst had.

Iig hartelijk bedankt voor de leuke discussie ;)

- ThaFreak007

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op 09 oktober 2004 @ 02:31:
Het kan wel anders hoor; je kan eerst je stack bijwerken met een asm directive en dan je pointer force casten via een union...of je space shuttle dan ook nog landen kan is de vraag, maar het kan wel.
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
#include <iostream>
#include <algorithm>


/*
B8 78 56 34 12   mov         eax,12345678h 
87 04 24         xchg        eax,dword ptr [esp] 
50               push        eax  
E8 0C EF FF FF   call        testfunc (41A0EAh) 
58               pop         eax  
89 04 24         mov         dword ptr [esp],eax 
C3               ret              
*/

template <class T, void (T::*FUNC) ()>
class Thunk
{
private:
    unsigned char asmcode[19];

    static void __cdecl callstub (void * retAddr, T * t)
    {
        (t->*FUNC) ();
    }

    typedef void (__cdecl * func_t) ();

public:
    Thunk (T * t)
    {
        static const unsigned char data[19] =
        {
            0xb8, 0, 0, 0, 0, 0x87, 0x04, 0x24, 0x50, 0xe8,
            0, 0, 0, 0, 0x58, 0x89, 0x04, 0x24, 0xc3
        };

        std::copy (data, data + 19, asmcode);
        (T *&)asmcode[1] = t;
        (int &)asmcode[10] = (int)callstub - (int)&asmcode[14];
    }


    operator func_t ()
    {
        return (func_t)&asmcode;
    }
};


struct A
{
    int i;
    void f ()
    {
        std::cout << i << std::endl;
    }
};


void CStyleFunc (void (__cdecl * func)())
{
    func ();
}



int main ()
{
    A a;
    a.i = 1234;
    Thunk<A, A::f> t (&a);

    CStyleFunc (t);
}

[ Voor 7% gewijzigd door .oisyn op 11-10-2004 11:49 ]

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.


Verwijderd

Leuk zeg! Mischien nog even in de comment zetten dat het x86 machinecode is? ;)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Hahaha _/-\o_ _/-\o_ 0wn3d :P Ook tijd over? ;)

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Voor GoT altijd ;)

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...

Hehe, slijmbal ;) Hmmm vraag me af hoe het op een spaceshuttle met sparc cluster draait ;)
Zo zien we maar weer; alles kan...hoewel het soms niet leuk is...

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

M'n asm code is trouwens best lomp zie ik nu, komt omdat ik het eerst anders aan wilde pakken. Ik exchange nu het returnadres op de stack met een pointer naar T, alleen je kunt natuurlijk net zo goed meteen die pointer pushen, callstub aanroepen, 4 bij esp optellen en dan een ret doen, aangezien je toch geen verdere parameters hebt.

Wat ook zou kunnen is callstub geheel ontwijken en zelf de call naar memberfunctie doen, hoewel je dan wel een pointer naar die memberfunctie op kunt slaan omdat je anders compile info nodig hebt of de functie een virtual functie is, waar die in de vtable staat, etc.. Als je het via een pointer naar memberfunctie doet dan kun je 'm geloof ik direct aanroepen door ecx naar de T* te laten wijzen en dan een call naar de functiepointer te doen, maar ik had even geen zin om dat allemaal uit te zoeken ;)

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