2017-09-28 5 views
2

J'ai une classe de base, une classe dérivée et une fonction de membre virtuel. J'ai aussi une fonction qui prend une référence de classe de base et fait un appel polymorphes à la fonction membre:Pourquoi std :: bind évite-t-il une liaison tardive lors de l'utilisation d'une référence par renvoi?

#include <iostream> 
#include <functional> 
class Base 
{ 
public: 
    Base() {} 
    virtual int getnum() { return 1; } 
}; 

class Derived : public Base 
{ 
public: 
    Derived() {} 
    virtual int getnum() { return 2; } 
}; 

int getnumref(Base& b) { return b.getnum(); } 

int main() 
{ 
    Derived d; 
    Base& bref = d; 
    std::cout << getnumref(bref) << std::endl; 
} 

Ici, la liaison tardive se produit, et la sortie est 2.

Mais si j'ajoute maintenant les lignes suivantes à la fonction main() afin de prédéfinir l'argument de la fonction, puis l'appeler:

std::function<int()> boundgetnumref = std::bind(getnumref, bref); 
std::cout << boundgetnumref() << std::endl; 

alors la sortie de la dernière ligne est 1, c'est-à-dire que la liaison anticipée se produit ici et que la fonction membre de la classe de base est appelée.

Si j'utilise des pointeurs, à savoir

//... 
int getnumptr(Base* b) { return b->getnum(); } 
//... 
int main() 
{ 
    Derived d; 
    Base* bptr = &d; 
    std::cout << getnumptr(bptr) << std::endl; 
    std::function<int()> boundgetnumptr = std::bind(getnumptr, bptr); 
    std::cout << boundgetnumptr() << std::endl; 
} 

alors la sortie des deux appels cout est 2. Pourquoi une liaison précoce a-t-elle lieu lorsque j'utilise la référence de passage avec std::bind, et pas autrement?

+2

Légèrement sans lien: n'utilisez pas 'std :: bind' dans le code moderne, préférez toujours lambdas. Voir: https://youtu.be/zt7ThwVfap0?t=1754 –

Répondre

1

std::bind stocke les arguments capturés par valeur provoquant une copie de tranchage de Derived à Base.

Si vous passez std::reference_wrapper (un pointeur) qui suffit de copier le pointeur, de sorte que la copie tranchage ne se produit pas:

std::function<int()> boundgetnumref = std::bind(getnumref, std::ref(bref)); 

Préférez lambdas cependant, ils sont les meilleures pratiques: plus facile à écrire, lire et Plus efficace:

auto boundgetnumref = [&bref]() { return getnumref(breg); }