2016-01-09 3 views
2

Je comprends la différence entre la liaison statique et dynamique en ce sens que les appels de méthodes sont déterminés au moment de la compilation pour la liaison statique - tandis que les appels de méthode sont déterminés au moment de l'exécution pour la liaison dynamique. Une chose que je ne comprends pas est pourquoi vous devez passer par référence ou pointeur pour la liaison dynamique. J'ai essayé de regarder en ligne mais je suis toujours confus. Est-ce parce que quand vous passez par la valeur, vous passez une copie qui signifie qu'elle doit être initialisée ce qui signifie qu'elle est découpée?Comportement de liaison statique et dynamique C++

Par exemple, Pet est une classe de base et Dog est une classe dérivée.

maintenant ...

void print(Pet p) {} // Calls print from the pet class 
void print(Pet &p) {} // Calls print from the type of pet object being passed. For example, Dog::print() rather than Pet::print() 

Si quelqu'un pouvait me l'expliquer mieux ce sera vraiment me rendre heureux

Merci

+3

Ces choses sont orthogonales. Il n'y a aucune exigence forte pour avoir des paramètres de référence pour _dynamic binding_. Peut-être mélangez-vous quelque chose avec le polymorphisme dynamique. –

Répondre

1

Vous confondez beaucoup de choses avec par appel -value et appel par référence.

void print(Pet p); 

C'est une déclaration print d'être une fonction renvoyant void et en prenant un paramètre de Pet par valeur nommée p. Ceci est appel par valeur.

void print(Pet &p); 

C'est une déclaration print d'être une fonction renvoyant void et en prenant un paramètre de Pet par référence nommé p. C'est appel par référence.

+0

L'OP ne confond pas nécessairement les choses. Les questions de valeur-by et de référence sont directement liées au comportement de liaison statique x dynamique. Vois ma réponse. –

1

Votre hypothèse est à peu près correcte, pas pour la fonction print elle-même, mais pour les fonctions membres de Pet éventuellement appelée à l'intérieur. La fonction print qui utilise valeur de passage prend un objet de base Pet. Par conséquent, le compilateur est libre de lier l'appel statiquement (et un objet Dog passé à lui serait coupé).

Mais pour votre fonction print qui utilise passe par référence, le compilateur doit lier l'appel à eatdynamiquement parce qu'il ne sait pas quel objet exact vit à cette adresse. Jetez un oeil sur le code suivant.

#include <iostream> 

struct Pet { 
    virtual void eat() const { std::cout << "pet" << std::endl; } 
}; 

struct Dog : Pet { 
    void eat() const /*override*/ { std::cout << "dog" << std::endl; } 
}; 

// Option 1: void print(Pet p) { p.eat(); } 
// Option 2: void print(Pet& p) { p.eat(); } 

int main() { 
    Pet* p = new Dog; 
    print(*p); 
    delete p; 
    // In c++ 11 use override and std::unique_ptr. 
    return 0; 
} 

Si vous décommentez l'option 1, c'est le code généré. Notez que l'appel à manger est statiquement résolu.

__Z5print3Pet: 
     .cfi_startproc 
     pushq %rbp 
Ltmp2: 
     .cfi_def_cfa_offset 16 
Ltmp3: 
     .cfi_offset %rbp, -16 
     movq %rsp, %rbp 
Ltmp4: 
     .cfi_def_cfa_register %rbp 
     callq __ZNK3Pet3eatEv  # HERE eat GETS CALLED. 

Cependant, si vous maintenant l'option 2 uncomment, le compilateur doit effectuer un appel indirect, lié à l'exécution .

__Z5printR3Pet:       
     .cfi_startproc 
     pushq %rbp 
Ltmp2: 
     .cfi_def_cfa_offset 16 
Ltmp3: 
     .cfi_offset %rbp, -16 
     movq %rsp, %rbp 
Ltmp4: 
     .cfi_def_cfa_register %rbp 
     subq $16, %rsp 
     movq %rdi, -8(%rbp) 
     movq -8(%rbp), %rdi 
     movq (%rdi), %rax 
     callq *(%rax)   # HERE eat GETS INDIRECTLY CALLED.