2016-07-25 24 views
5

Ich habe über einige Beispiel-Code, der sowohl this->functionname() und classname::functionname() zum Aufrufen von Funktionen in der gleichen Klasse verwendet.Wann sollte ich this-> Funktionsname() über Klassenname :: Funktionsname() für den Aufruf von Member-Funktionen verwenden?

Gibt es tatsächlich einen Unterschied zwischen diesen beiden Methoden?

Gibt es auch einen Unterschied zwischen diesen Methoden und nur den Aufruf der Funktion mit functionname()?

Danke.

+0

Antwort auf diese Frage ist guter Kandidat für dieses neue Dokumentation Dingen. – Dialecticus

Antwort

4

Wie in C++ üblich, sind die Dinge weniger einfach als Sie vielleicht denken.

Es gibt drei Möglichkeiten, Elementfunktionen aufzurufen.

  1. rufen Sie die Funktion: foo();
  2. Anruf mit this: this->foo();
  3. den Namen der Klasse verwenden: classname::f();

Nummern # 1 und # 2 äquivalent sind, einige Leute es vorziehen, # 2, weil Es ist klarer, dass dies eine Mitgliedsfunktion ist und keine globale Funktion (diese Leute sind in einer Minderheit).

Ob # 3 von # 1 und # 2 abweicht, hängt davon ab, ob es sich bei der aufgerufenen Funktion um eine virtuelle Funktion handelt. Wenn es nicht virtuell ist, gibt es keinen Unterschied.Wenn es ist virtuelle und gibt es eine weitere abgeleitete Überschreibung dieser Funktion dann # 1 und # 2 wird die abgeleitete Funktion und # 3 ruft die Überschreibung aufgerufen, die in dieser Klasse vorhanden ist (oder wenn es keine Überschreibung in dieser Klasse , die nächste Superklasse).

Die Ausnahme zum vorherigen Absatz ist, wenn die Call-Site in einem Konstruktor oder einem Destruktor ist. In diesem Fall, selbst wenn die Funktion virtuell ist, wird sich # 1 und # 2 genauso verhalten wie # 3 (rufen Sie die Überschreibung in dieser oder der nächsten Superklasse auf).

Wenn die Funktion static ist, dann ist # 2 ungültig und # 1 und # 3 sind äquivalent, wenn sie innerhalb der Klasse aufgerufen werden, aber # 3 wird benötigt, wenn sie von außerhalb der Klasse aufgerufen werden.

Ich hoffe, dass ich nichts übersehen haben :)

Dinge, die ich verpasst haben:

  • this benötigt werden, wenn die Funktion durch eine globale Wieder erklärte in der Berufung versteckt Funktion. Siehe @Dutow's answer.
  • this kann nützlich sein im Umgang mit two phase lookup (wenn Vorlagen beteiligt sind). Danke an @Alejandro für seinen Kommentar.
  • Ich vermute, dass mit using kann noch mehr Schlamm ins Wasser werfen, aber ich kann nicht belästigt werden, im Moment (caveat emptor) zu untersuchen.

die Tat nicht so einfach, wie man vielleicht denken ...

+0

Sie könnten auch das Argument machen, dass 'this 'auch für die richtige [Zwei-Phasen-Suche] benötigt wird (http://blog.llvm.org/2009/12/drawed-two-phase-name-lookup.html?m= 1) in bestimmten Fällen – Alejandro

+0

@ Alejandro, danke, ich habe meine Antwort aktualisiert. – Motti

3

Normalerweise? Sie sind gleich. Je nach Kontext können sie jedoch unterschiedliche Dinge bedeuten.

Betrachten wir zum Beispiel die folgende extremes Beispiel (tun dies in einem realen Projekt nicht!):

void f() { std::cout << "f" << std::endl; } 

class Cl { 
public: 
    void f() { std::cout << "Cl::f" << std::endl; } 
    void g() { 
     struct Cl { 
      static void f() { std::cout << "inside Cl::f" << std::endl; } 
     }; 
     void f(); 

     f(); 
     Cl::f(); 
     this->f(); 
    } 
}; 

int main() 
{ 
    Cl a; 
    a.g(); 

    return 0; 

} 

Bei diesem wird die Erklärung der globalen f Schatten der Member-Methode f, was in der Programmausgabe f anstelle von Cl::f.

Die lokale struct Cl Schatten auch seine eigenen Typname, was in Cl::f() ruft es ist statische f Methode.

Nur der Aufruf this->f() führt explizit zum Aufruf Cl::f.

Die Variante mit dem Typnamen wird auch häufig verwendet, wenn Sie Methoden in der Elternklasse aufrufen, wenn Sie Vererbung und überschreiben virtuelle Methoden verwenden - aber das ist technisch nicht die gleiche Klasse.

+0

TIL, dass Sie eine Funktion innerhalb einer Funktion deklarieren können (und ich dachte, dass meine Antwort erschöpfend war ...) – Motti

+0

Und ich schaffte es auch, 'Cl :: f' zu bricken! :) – Dutow

+0

Sie, mein Herr, sind böse! Gut gemacht (Ich habe Ihre Antwort in meiner erwähnt). – Motti

1

Ich denke, ein Grund, dies zu verwenden, ist in diesem Szenario. Z.B.

class A 
{ 
public: 
    void foo() { this->doFoo(); } //equivalent to just doFoo(); 
    void foo2() { Abstract::doFoo(); } 
private: 
    virtual void doFoo() { /* do stuff */ } 
}; 

Im Snippet wenn foo nannte es doFoo in den meisten abgeleiteten Klasse aufrufen wird. Wenn Sie foo2 aufrufen, wird die Basisimplementierung immer aufgerufen, auch wenn sie überschrieben wurde.