наследование — C ++ Static & amp; Динамическое связывание

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

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

Например, 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()

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

Спасибо

2

Решение

Вы путаете много вещей с вызов по значению а также позвонить по ссылке.

void print(Pet p);

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

void print(Pet &p);

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

1

Другие решения

Ваше предположение примерно верно, не для print функционировать сам по себе, но для Petфункции-члены в конечном итоге вызываются внутри него. print функция, которая использует Передача по стоимости занимает базу Pet объект. Поэтому компилятор может связать вызов статическиDog переданный объект будет разрезан).

Но для вашего 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.
1

По вопросам рекламы [email protected]