Да
Возможно, вы захотите изменить вопрос, однако
Рассмотрите этот код C ++, где Derived
явно полиморфен (да, я не удалялобъект):
class Base
{
public: int foo(){ return 1; }
};
class Derived: public Base
{
public: int foo(){ return 2; };
};
int main()
{
Base* b = new Derived();
return b->foo(); //Returns 1
}
Сборка, сгенерированная gcc:
main:
.LFB2:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $1, %ecx
call _Znwm
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rcx
call _ZN4Base3fooEv
addq $48, %rsp
popq %rbp
ret
Как вы можете видеть, нет косвенного перехода / вызова.
Это потому, что полиморфизм здесь не имеет значения (хотя это необходимо), виртуальные методы .
Тогда ответ становится
Нет
Если под косвенным переходом / вызовом вы подразумеваете каждый метод, который использует значение времени выполнения для вычисления цели перехода / вызова (включая такие вещи, как ret
, call []
, call reg
, jr
, jalr
).
Рассмотрим этот источник
#include <iostream>
class Base
{
public: virtual int foo(){ return 1; }
};
class Derived: public Base
{
public: int foo(){ return 2; };
};
class Derived2: public Base
{
public: int foo(){ return 3; };
};
int main()
{
int a;
Base* b = 0; //don't remember the header for std::nullptr right now...
std::cin >> a;
if (a > 241)
b = new Derived();
else
b = new Derived2();
return b->foo(); //Returns what?
}
Результат зависит от пользовательского ввода, архетипического значения времени выполнения, поэтому должна быть вызванная подпрограмма, а статический адрес не подойдет.
Обратите внимание, что в этом случае компилятор может использовать переход к вызовам со статическим адресом (так как вызывается либо Derived2::foo
, либо Derived::foo
), но это, как правило, невозможно (у вас может быть несколько объектных файлов без источника, вы можете иметьуказатель псевдонимов, указатель b
может быть установлен внешней библиотекой и т. д.).