Domanda

Prima di tutto devo ammettere che le mie capacità di programmazione sono piuttosto limitate e ho preso il controllo di un progetto OOP C ++ (davvero piccolo) in cui provo a inserire le mie cose. Sfortunatamente sto riscontrando un problema che va oltre le mie conoscenze e spero di trovare un aiuto qui. Sto lavorando con una libreria di terze parti (che non può essere modificata) per acquisire immagini da una fotocamera e qui userò alcuni nomi di segnaposto.

La libreria di terze parti ha una funzione " ThirdPartyGrab " per avviare un live grab continuo e prendere un puntatore a una funzione che verrà chiamata ogni volta che arriva un nuovo frame. Quindi in una normale applicazione C va così:

ThirdPartyGrab (HookFunction);

" HookFunction " deve essere dichiarato come:

long _stdcall HookFunction (long, long, void*);

o " BUF_HOOK_FUNCTION_PTR " che è dichiarato come

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);

Ora ho un'applicazione C ++ e una classe " MyFrameGrabber " che dovrebbe incapsulare tutto ciò che faccio. Quindi ho inserito la funzione hook come membro privato in questo modo:

ThirdPartyGrab (..., HookFunction, ...);

Inoltre esiste una funzione di vuoto pubblico " StartGrab " nella mia classe che dovrebbe iniziare il Grab. All'interno cerco di chiamare:

static MyFrameGrabber& instance()
{
        static MyFrameGrabber _instance;
        return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file

che (non a caso) fallisce. Dice che la chiamata di funzione a MyFrameGrabber :: HookFunction manca l'elenco degli argomenti e dovrei provare a usare & amp; MyFrameGrabber :: HookFunction per creare invece un puntatore. Tuttavia, passando " & amp; MyFrameGrabber :: HookFunction " risulta invece un altro errore che non può essere convertito in BUF_HOOK_FUNCTION_PTR.

Dopo aver letto le C ++ FAQ puntatori alla funzione Penso di aver capito il problema ma non riesco a trovare una soluzione. Ho provato a rendere statica la funzione hook ma anche questo provoca un errore di conversione. Ho anche pensato di mettere la funzione hook fuori dalla classe, ma ho bisogno di usare le funzioni di classe all'interno della funzione hook. C'è un altro modo o devo cambiare tutto il mio concetto?

MODIFICA 14.01.08: Ho provato la soluzione alternativa singleton poiché non riesco a modificare la libreria di terze parti e il puntatore vuoto è solo per i dati utilizzati all'interno della funzione hook. Sfortunatamente non ha funzionato come speravo .... Non so se la funzione statica debba essere in una classe separata, quindi l'ho inserita nel mio " MyFrameGrabber " classe:

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
    return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
    ThirdPartyGrab(..., call_hook, ...);
}

Nel mio file cpp ho la funzione call_hook:

MyFrameGrabber (void* x,
                const std::string &y, int z,
                std::string &zz);

Ma questo mi dà un errore in static MatroxFrameGrabber _instance; che non è stato trovato alcun costruttore standard corrispondente. È corretto perché il mio costruttore MyFrameGrabber è simile al seguente:

<*>

Ho provato a inserire un costruttore vuoto MyFrameGrabber (); ma questo provoca un errore del linker. Devo passare parametri vuoti al costruttore MyFrameGrabber nel singleton? Oppure devo avere una classe hook separata e, in caso affermativo, come posso accedere alle funzioni MyFrameGrabber? Grazie in anticipo.

SECONDA MODIFICA 15.01.08: Ho applicato le modifiche e ora vengono compilate e collegate. Purtroppo non riesco ancora a testarlo in fase di runtime perché è una DLL e non ho ancora Debug Caller Exe e ci sono altri problemi durante l'inizializzazione, ecc. Contrassegnerò il post come risposta perché sono sicuro che questo è il modo giusto per farlo.

È stato utile?

Soluzione

Il motivo " & amp; MyFrameGrabber :: HookFunction " non può essere convertito in BUF_HOOK_FUNCTION_PTR è che, essendo un membro della classe, ha implicitamente come primo parametro il " questo " puntatore, quindi non è possibile convertire una funzione membro in una funzione non membro: le due firme sembrano uguali ma in realtà sono diverse.

Dichiarerei un'interfaccia, definendo la funzione da chiamare, fare in modo che la tua classe la implementasse e passasse l'oggetto stesso invece del callback (puoi pensare a un'interfaccia come la sostituzione orientata agli oggetti di un puntatore a funzione):

class IHookInterface{
public:
    virtual long HookFunction(long, long, void*) = 0;
};
 class HookClass : public IHookInterface{
public:
    virtual long Hook(long, long, void*) {
        // your code here... 
    }
};

// nuova definizione: ThirdPartyGrab (..., IHookInterface, ...);

EDIT - altra possibile soluzione nel caso in cui non sia possibile modificare la libreria: utilizzare un singleton anziché una funzione statica.

class HookClass{
public:
    static HookClass& instance(){
        static HookClass _instance;
        return _instance;
    }
    long Hook(long, long, void*) {
        // your code here... 
    }
};

long call_hook(long x,long y,void * z){
    return HookClass::instance().Hook(x,y,z);
}

SECONDA MODIFICA: potresti modificare leggermente la classe singleton con un metodo di inizializzazione per chiamare il costruttore con i parametri corretti, ma forse non è più elegante della seguente soluzione, che è più semplice:

class HookClass{
public:

    HookClass(string x,string y...){
    }

    long Hook(long, long, void*) {
        // your code here... 
    }
};

static HookClass * hook_instance = 0;

long call_hook(long x,long y,void * z){
    if (0 != hook_instance){
        return hook_instance->Hook(x,y,z);
    }
}

int main(){
    hook_instance = new HookClass("x","y");
    ThirdPartyGrab(..., call_hook, ...);
}

Altri suggerimenti

Il tuo metodo di membro privato ha un puntatore this implicito come primo argomento. Se lo scrivi, è ovvio che le firme della funzione non corrispondono.

È necessario scrivere una funzione membro statica, che può essere passata come funzione callback alla libreria. L'ultimo argomento di HookFunction , un void * , mi sembra molto simile a un cookie, in cui è possibile passare il proprio puntatore.

Quindi, tutto sommato, dovrebbe essere qualcosa del genere:

class MyClass {
  long MyCallback(long, long) {
    // implement your callback code here
  }

  static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) {
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b);
  }
public:
  void StartGrab() {
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...);
  }
};

Questo ovviamente funziona solo se l'argomento void * sta facendo quello che ho detto. La posizione del this nella chiamata ThirdPartyGrab () dovrebbe essere facile da trovare quando si dispone della firma della funzione completa inclusi i nomi dei parametri disponibili.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top