11

Wenn ich einen Mitgliedsfunktionszeiger an eine Klasse innerhalb einer der Mitgliedsfunktionen dieser Klasse zurückgebe, muss ich noch die Klasse angeben. Ich kann die Adresse nicht einfach nehmen. Zum Beispiel this code works fine:Warum erfordert die Verwendung eines Mitgliedsfunktionszeigerwerts die Klassennamenqualifizierung auch innerhalb der Klasse?

class Foo { 
public: 
    void func(int param) { cout << param << endl; } 
    void (Foo::*getPointer())(int) { return &Foo::func; } 
}; 

Aber wenn in getPointer Ich versuche einfach tun: return &func ich diesen Fehler:

prog.cpp: In member function ' void (Foo::* Foo::getPointer())(int) ':
prog.cpp:8:43: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ' &Foo::func ' [-fpermissive]
void (Foo::*getPointer())(int) { return &func; }

Warum ich die Klasse angeben muß, wenn das ist der Kontext, den ich in bin?

+0

@JoachimPileborg Scope offensichtlich. Wenn es eine Nichtmitgliedsvariable mit demselben Namen wie die Klassenvariable gibt, muss ich die Klasse nicht angeben. –

+1

Ah ich habe deine Frage missverstanden, du fragst nach der Notwendigkeit von 'Foo ::' in '& Foo :: func'. –

+1

@JoachimPileborg Ja, es macht mich verrückt, warum der Compiler das nicht herausfinden kann. Ich muss nicht für statische Funktionen, Elementvariablen, beim Aufrufen von Funktionen oder sogar für die Adresse einer Membervariablen angeben. aber aus irgendeinem Grund, wenn ich die Adresse einer Funktion möchte ich angeben. –

Antwort

3

Pointers und Zeiger auf Mitglieder sind unterschiedliche Typen, können wir das aus dem Abschnitt des Entwurfs C++ Standard siehe Abschnitt 3.9.2 [basic.compound], die eine Verbindung Typ für Zeiger sowie Zeiger auf nicht-statische Klassenelement und Hinweise:

Static class members are objects or functions, and pointers to them are ordinary pointers to objects or functions

Dieses Problem dabei ist ich denke, auch in this quote in an answer from Johannes vom Annotated C++ Reference Manual(ARM) beschrieben:

Note that the address-of operator must be explicitly used to get a pointer to member; there is no implicit conversion ... Had there been, we would have an ambiguity in the context of a member function ... For example,

void B::f() { 
    int B::* p = &B::i; // ok 
    p = B::i;   // error: B::i is an int 
    p = &i;   // error: '&i'means '&this->i' 
         // which is an 'int*' 

    int *q = &i;  // ok 
    q = B::i;   // error: 'B::i is an int 
    q = &B::i;  // error: '&B::i' is an 'int B::*' 
} 

insbesondere diese l ines:

int B::* p = &B::i; // OK 

und:

p = &i; // error: '&i'means '&this->i' which is an 'int*' 

die Differenz zwischen den qualifizierten und den nicht qualifizierten Namen zu demonstrieren.

+0

Ich denke, ich muss eine Kopie von ARM abholen, um neben meinem D & E zu gehen, Sie können kein pdf von entweder kaufen :-( –

+0

Ich denke, ich habe es auf Ihre Antwort in Kombination mit [ dyps Kommentar] (http: // stackoverflow.com/questions/32842429/why-nimmt-ein-Mitglied-function-Zeiger-Wert-erfordert-class-name-qualificatio/32845696 # comment53523542_32842429). Wenn ich '& B ::' mache, bekomme ich den Offset nicht die absolute Adresse. Ich denke, ich muss verstehen, dass alle Methoden von Offset aufgerufen werden, * nicht * tatsächliche Adresse? –

+1

@ JonathanMee, das ist eine mögliche Implementierung, Lesen [Zeiger zu Mitgliederfunktionen sind sehr seltsame Tiere] (http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx) sollte hilfreich sein . –

3

(... es gab eine falsche Antwort ...)

Es in folgendem Zusammenhang mehr seltsam aussieht:

class Foo { 
public: 
    virtual void func(int param) { cout << param << endl; } 
    void call(int x) { Foo::func(x); } 
    void (Foo::*getPointer())(int) { return &Foo::func; } 
}; 

class Bar : public Foo { 
public: 
    void func(int param) override { cout << "Hello world!" << endl; } 
}; 


int main() { 

    Foo *a = new Bar(); 
    auto p = a->getPointer(); 
    (a->*p)(4); 
    a->call(4); 

    return 0; 
} 

Der Ausgang ist

Hello world
4

Aufruf Foo::func ist Ein Anruf von func in Foo Klasse beim Anruf &Foo::func ist ein virtueller Anruf.

+0

Vielen Dank. Es macht jetzt alles Sinn. –

+2

Das ist falsch. Eine nicht-statische Mitgliedsfunktionsadresse ist kein Zeiger und erfordert, dass ein "Dies" verwendet wird, so dass es zur Kompilierungszeit nicht zu "einer Adresse" aufgelöst werden muss. Außerdem, wenn 'mp' auf' Foo :: func' zeigt und Sie es in einer 'Bar' Instanz aufrufen, dann wird' Bar :: func' Version aufgerufen. – 6502

+0

@ 6502 Arg! Du schießt die einzige vernünftige Erklärung ab, die ich gehört habe! –

Verwandte Themen