2016-07-25 8 views
5

Przeglądałem przykładowy kod, który używa zarówno this->functionname(), jak i classname::functionname() do wywoływania funkcji w tej samej klasie.Kiedy należy użyć tej -> functionname() nad nazwą klasy :: functionname() do wywoływania funkcji członka?

Czy rzeczywiście istnieje różnica między tymi dwoma metodami?

Czy istnieje różnica między tymi metodami i po prostu wywołanie funkcji przy użyciu functionname()?

Dzięki.

+0

Odpowiedź na to pytanie jest dobrym kandydatem do tego nowego rodzaju lasera Documentation. – Dialecticus

Odpowiedz

4

Jak zwykle w C++ rzeczy są mniej proste, niż mogłoby się wydawać.

Istnieją trzy sposoby wywoływania funkcji członków.

  1. tylko wywołać funkcję: foo();
  2. wezwanie z this: this->foo();
  3. używać nazwy klasa to: classname::f();

Numery # 1 i # 2 są równoważne, niektórzy ludzie wolą # 2, ponieważ jest jaśniejsze, że jest to funkcja członkowska, a nie funkcja globalna (ci ludzie są w mniejszości).

To, czy # 3 różni się od # 1, a # 2 zależy od tego, czy wywoływana funkcja jest funkcją wirtualną. Jeśli jest to nie-wirtualne, nie ma różnicy.Jeśli to jest wirtualny i istnieje więcej pochodnych zastąpienia tej funkcji następnie # 1 i # 2 będą nazywane pochodną funkcją, a # 3 wywoła zastąpienie, które istnieje w tej klasie (lub jeśli nie ma żadnych przesłonięcie w tej klasie , najbliższa super-klasa).

Wyjątkiem od poprzedniego akapitu jest sytuacja, gdy strona wywoławcza znajduje się w konstruktorze lub destruktorze. W tym przypadku, nawet jeśli funkcja jest wirtualna # 1, a # 2 będzie zachowywać się tak samo jak # 3 (wywołaj nadpisanie w tej lub najbliższej super-klasie).

Dodatkowo, jeśli funkcja jest static, to # 2 jest nieważne, a # 1 i # 3 są równoważne, gdy są wywoływane z poziomu klasy, ale # 3 jest potrzebny, gdy zostanie wywołany spoza klasy.

Mam nadzieję, że nie przegapisz niczego :)

Czego nieodebrane:

  • this mogą być potrzebne, jeśli funkcja jest ukryty przez globalną re-zadeklarowana wewnątrz powołania funkcjonować. Zobacz @Dutow's answer.
  • this może być przydatny podczas pracy z two phase lookup (gdy szablony są zaangażowane). Dzięki @Alejandro za komentarz.
  • Zgaduję, że użycie using może rzucić trochę więcej błota w wodzie, ale nie mogę się tym przejmować (zablokować emptora).

Rzeczywiście, nie jest tak proste, jak mogłoby się wydawać ...

+0

Można również wysunąć argument, że 'ten' jest również potrzebny do poprawnego [dwuetapowego wyszukiwania] (http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html?m= 1) w niektórych przypadkach – Alejandro

+0

@Alejandro, dzięki, zaktualizowałem swoją odpowiedź. – Motti

3

Zwykle? Oni są tacy sami. Ale w zależności od kontekstu mogą one oznaczać różne rzeczy.

Na przykład rozważmy następujący skrajny przykład (nie rób tego w rzeczywistym projekcie!):

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; 

} 

w tym, deklaracji globalnych f cieni metoda członek f, w wyniku program wyprowadzający f zamiast Cl::f.

Lokalna struct Cl również cienie to własna nazwa pliku, co powoduje, że Cl::f() nazywa się statyczną metodą f.

Tylko wywołanie this->f() powoduje jawne wywołanie Cl::f.

Wariant o nazwie typowej jest również powszechnie używany, gdy chcesz wywołać metody w klasie nadrzędnej podczas dziedziczenia i zastępowania metod wirtualnych - ale nie jest to z technicznego punktu widzenia ta sama klasa.

+0

TIL, w którym można zadeklarować funkcję wewnątrz funkcji (i myślałem, że moja odpowiedź była wyczerpująca ...) – Motti

+0

Udało mi się też zamalować 'Cl :: f'! :) – Dutow

+0

Jesteście sir, są źli! Dobra robota (wspomniałem twoją odpowiedź w mojej). – Motti

1

Myślę, że jednym z powodów, aby skorzystać z tego jest w tym scenariuszu. Na przykład.

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

we fragmencie Dzwoniąc foo będzie powoływać doFoo w klasie większość pochodzi. Podczas wywoływania foo2 zawsze będzie wywoływać podstawową implementację, nawet jeśli została przesłonięta.

Powiązane problemy