Je travaille sur quelqu'un d'autre du code en C++, et j'ai trouvé un appel étrange à une certaine fonction func()
. Voici un exemple:
if(condition)
func();
else
(*this).func();
Quelle est la différence entre func()
et (*this).func()
?
Quels sont les cas où l'appel à func()
et (*this).func()
Exécutera un code différent?
Dans mon cas, func()
n'est pas une macro. Il s'agit d'une fonction virtuelle dans la classe de base, avec une implémentation à la fois dans la classe de base et dérivée, et sans func()
libre. if
est situé dans une méthode de la classe de base.
Il y a effectivement une différence, mais dans un contexte très non trivial. Considérez ce code:
void func ( )
{
std::cout << "Free function" << std::endl;
}
template <typename Derived>
struct test : Derived
{
void f ( )
{
func(); // 1
this->func(); // 2
}
};
struct derived
{
void func ( )
{
std::cout << "Method" << std::endl;
}
};
test<derived> t;
Maintenant, si nous appelons t.f()
, la première ligne de test::f
Invoquera la fonction gratuite func
, tandis que la deuxième ligne appellera derived::func
.
Il est impossible de le dire à partir de l'extrait de code, mais il existe peut-être deux objets appelables appelés func()
. Le (*this).func();
s'assure que la fonction membre est appelée.
Un objet appelable peut être (par exemple) une expression functor
ou lambda
:
foncteur
struct func_type
{
void operator()() const { /* do stuff */ }
};
func_type func; // called using func();
lambda
auto func = [](){ /* do stuff */ }; // called using func();
Par exemple:
#include <iostream>
class A
{
public:
// member
void func() { std::cout << "member function" << '\n'; }
void other()
{
// lambda
auto func = [](){ std::cout << "lambda function" << '\n'; };
func(); // calls lambda
(*this).func(); // calls member
}
};
int main()
{
A a;
a.other();
}
Sortie:
lambda function
member function
Un autre cas où ces deux lignes appellent des fonctions différentes:
#include <iostream>
namespace B
{ void foo() { std::cout << "namespace\n"; } }
struct A {
void foo() { std::cout << "member\n"; }
void bar()
{
using B::foo;
foo();
(*this).foo();
}
};
int main ()
{
A a;
a.bar();
}
Avec un nom dépendant du type, il peut être différent:
void func() { std::cout << "::func()\n"; }
struct S {
void func() const { std::cout << "S::func()\n"; }
};
template <typename T>
struct C : T
{
void foo() const {
func(); // Call ::func
(*this).func(); // Call S::func
}
};