Frage

Ich habe Code ähnlich wie dies in meiner Anwendung:

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);

Die Frage ist - Was soll MYSTERYTYPE sein? weder void * noch int Arbeit trotz des Wertes & A :: b gerade fein gedruckt wird, wenn Sie Ausgabe, die es durch eine printf.

Klärungen: Ja, & A :: b wird unter C ++ definiert. Ja, ich bin versucht, den Offset zu einer Klasse Mitglied zu erhalten. Ja, ich bin sein heikel.

Edit: Oh, ich kann offsetof () verwenden. Trotzdem danke.

War es hilfreich?

Lösung

Sie haben ein Datenelement Zeiger auf zwei voneinander unabhängige Klassen. Nun, man kann nicht eine gemeinsame Art finden, die beiden Zeiger halten können. Es wird nur funktionieren, wenn der Funktionsparameter ein Datenelement Zeiger auf ein Mitglied der abgeleitet ist, weil es das Element enthält auch garantiert wird, wenn eine Base enthält es:

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

Aktualisieren : Ich glaube, ich schreiben soll, warum die oben Konvertiten aus a::* implizit b::*. Schließlich haben wir in der Regel b* a*! Bedenken Sie:

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

Wenn die oben gültig wäre, würden Sie wirklich viel vermasseln. Die oben ist nicht gültig, weil Umwandlung von b::* zu a::* ist nicht implizit. Wie Sie sehen, zugewiesen wir einen Zeiger :: c b, und dann könnten wir dereferenzieren es eine Klasse verwenden, die es gar nicht enthalten! (e). Der Compiler erzwingt diese Reihenfolge:

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

Es nicht jetzt zu kompilieren, weil e nicht von b abgeleitet wird, die Klasse der Elementzeiger Zeiger gehört. Gut! Im Folgenden ist jedoch sehr gültig und kompiliert, natürlich (geänderte Klassen a und b):

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

Um es für Ihren Fall funktioniert, müssen Sie Ihre Funktion eine Vorlage machen:

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

Nun wird der Compiler automatisch ableiten, die richtige Klasse, die das angegebene Element Zeiger zu gehört.

: Sie werden die Instanz neben der Elementzeiger tatsächlich davon Gebrauch machen passieren müssen
template<typename Class>
void DoThings (Class & t, int Class::*arg) { 
    /* do something with arg... */ 
    (t.*arg) = 10;
}

Wenn Sie nur einige Mitglieder festlegen mögen wissen Sie bereits zum Zeitpunkt des DoThings schreiben, die folgenden genügt:

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

Andere Tipps

Versuchen Sie einfach eine Funktion mit der Adresse einer ganzen Zahl zu nennen, die innerhalb eines A oder ein C Objekts leben geschieht? In diesem Fall Antwort Jeff McGlynn ist, ist der Weg zu gehen.

Andernfalls, wenn Sie wirklich versuchen, etwas heikel erfordern C ++ 's seltsam Zeiger-to-Mitglied Einrichtung zu tun (und Sie mit ziemlicher Sicherheit nicht):

Da Klassen A und C nichts zu tun haben, werden Sie eine Template-Funktion müssen beide behandeln:

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

Wenn C tatsächlich von A abgeleitet wurde, folgende funktionieren würde:

void DoThings(int A::*x);

& A :: b und & C :: d sind unsinnig, gibt es keine zugehörige Adresse. Versuchen Sie, den Versatz des Elements zu erhalten?

Sind Sie sicher, dass Sie nicht so etwas wie die folgenden?

DoSomething(&obj_a,&obj_a.b);

Wenn Sie Vorlagen verwenden, wie j_random_hacker vermuten lässt, und der Compiler kennt den Typ jeder Klasse an dem Punkt, wo Sie die Funktion aufrufen, die wörtliche Antwort auf Ihre Frage lautet: „template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER)“.

Hier ist, wie es in Ihrem Beispiel passen würde:

#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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top