2016-01-09 2 views
2

Я понимаю разницу между статической и динамической привязкой в ​​том смысле, что вызовы методов определяются во время компиляции для статической привязки, тогда как вызовы методов определяются во время выполнения для динамической привязки.C++ Статическое и динамическое поведение Binding

Одна вещь, которую я не понимаю, - это то, почему вам нужно передать ссылку или указатель на динамическую привязку. Я пробовал смотреть онлайн, но я все еще смущен. Это потому, что когда вы проходите по значению, вы передаете копию, что означает, что она должна быть инициализирована, что означает, что она нарезается?

Например, Pet является базовым классом, а Dog является производным классом.

Теперь ...

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() 

Если кто-то может объяснить мне лучше это будет действительно сделать меня счастливым

Благодаря

+3

Эти вещи ортогональны. Нет сильного требования иметь ссылочные параметры для _динамического связывания_. Может быть, вы что-то смешаете с _динамическим полиморфизмом. –

ответ

1

Вы путаете много вещей с вызовом по -значение и call-by-reference.

void print(Pet p); 

Это объявляя print быть функция, возвращающая void и принимает один параметр Pet по значения имени p. Это call-by-value.

void print(Pet &p); 

Это объявляя print быть функция, возвращающая void и принимает один параметр Pet по ссылки имени p. Это call-by-reference.

+0

ОП не обязательно путает вещи. Вопросы по-значения и по ссылке напрямую связаны со статическим x динамическим связыванием. См. Мой ответ. –

1

Ваше предположение примерно верно, но не для самой функции print, но для функций участника Pet, вызванных в ней. Функция print, которая использует пропущенный значение принимает базовый объект Pet. Поэтому компилятор может связывать вызов статически (и переданный ему объект 2 будет нарезанный).

Но для print функции, использующей прохода по ссылке, компилятор должен связать вызов eatдинамически, потому что он не знает, какой именно объект живет по этому адресу. Взгляните на следующий код.

#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; 
} 

Если вы раскомментируете вариант 1, это код, который генерируется. Обратите внимание, что вызов есть статически решены.

__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. 

Однако, если вы сейчас раскомментировать параметр 2, компилятор должен выполнить косвенный вызов, связанный в выполнения.

__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. 
Смежные вопросы