Domanda

Ho un codice simile a questo nella mia applicazione:

class A
{
  public: int b;
}

class C
{
  public: int d;
}

void DoThings (void *arg1, MYSTERYTYPE arg2);

A obj_a;
C obj_c;

DoThings(&obj_a, &A::b);
DoThings(&obj_c, &C::d);

La domanda è: cosa dovrebbe essere MYSTERYTYPE? né void * né int funzionano, nonostante il valore & amp; A :: b sia stampato bene se lo si stampa in outputf.

Chiarimenti: Sì, & amp; A :: b è definito in C ++. Sì, sto cercando di ottenere l'offset per un membro della classe. Sì, sono complicato.

Modifica: Oh, posso usare offsetof (). Grazie comunque.

È stato utile?

Soluzione

Hai un puntatore del membro dati a due classi non correlate. Bene, non riesci a trovare un tipo comune che può contenere entrambi i puntatori. Funzionerà solo se il parametro della funzione è un puntatore del membro dati a un membro del derivato, perché è garantito che contenga anche il membro, se una base lo contiene:

struct a { int c; }; struct b : a { }; int main() { int b::*d = &a::c; }

Aggiorna : penso che dovrei scrivere perché quanto sopra converte implicitamente da a::* a b::*. Dopotutto, di solito abbiamo da b* a a*! Prendere in considerazione:

struct a { };
struct b : a { int c; };
struct e : a { };
int main() { int a::*d = &b::c; e e_; (e_.*d) = 10; /* oops! */ }

Se quanto sopra fosse valido, potresti davvero rovinare tutto. Quanto sopra è non valido, poiché la conversione da e a b non è implicita. Come vedi, abbiamo assegnato un puntatore a b :: c, e quindi potremmo dereferenziarlo usando una classe che non lo contiene affatto! (a). Il compilatore applica questo ordine:

int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }

non riesce a compilare ora, poiché <=> non deriva da <=>, la classe a cui appartiene il puntatore del puntatore del membro. Buono! Quanto segue, tuttavia, è molto valido e compila, ovviamente (classi cambiate <=> e <=>):

struct a { int c; };
struct b : a { };
struct e : a { };
int main() { int e::*d = &a::c; e e_; (e_.*d) = 10; /* works! */ }

Per farlo funzionare nel tuo caso, devi rendere la tua funzione un modello:

template<typename Class>
void DoThings (int Class::*arg) { /* do something with arg... */ }

Ora, il compilatore dedurrà automaticamente la classe giusta a cui appartiene anche il puntatore del membro specificato. Dovrai passare l'istanza a fianco del puntatore del membro per utilizzarla effettivamente:

template<typename Class>
void DoThings (Class & t, int Class::*arg) { 
    /* do something with arg... */ 
    (t.*arg) = 10;
}

Se vuoi solo impostare un membro che già conosci al momento in cui scrivi DoThings, è sufficiente:

template<typename Class>
void DoThings (Class & t) {  
    t.c = 10;
}

Altri suggerimenti

Stai semplicemente cercando di chiamare una funzione con l'indirizzo di un numero intero che si trova all'interno di un oggetto A o C? In tal caso, la risposta di Jeff McGlynn è la strada da percorrere.

Altrimenti, se stai davvero cercando di fare qualcosa di complicato che richiede la strana struttura da puntatore a membro di C ++ (e quasi sicuramente non lo sei):

Poiché le classi <=> e <=> non sono correlate, sarà necessaria una funzione modello per gestire entrambi:

template <typename T>
void DoThings(int T::*x);

Se <=> fosse effettivamente derivato da <=>, funzionerebbe quanto segue:

void DoThings(int A::*x);

& amp; A :: b e & amp; C :: d sono privi di senso, non vi è alcun indirizzo associato. Stai cercando di ottenere l'offset del membro?

Sei sicuro di non voler qualcosa di simile al seguente?

DoSomething(&obj_a,&obj_a.b);

Se usi i template come suggerisce j_random_hacker e il compilatore conosce il tipo di ogni classe nel punto in cui chiami la funzione, la risposta letterale alla tua domanda è " template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER) " ;.

Ecco come si adatterebbe al tuo esempio:

#include <iostream>

class A {
public: 
    int b;
};

class C {
public: 
    int d;
};

template <typename CLASS>
void DoThings (CLASS * object, int CLASS::*MEMBER)
{
    std::cout << object->*MEMBER << std::endl;
}

A obj_a = { 2 };
C obj_c = { 4 };

int main (int argc, const char * argv[])
{
    DoThings(&obj_a, &A::b);
    DoThings(&obj_c, &C::d);
    return 0;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top