Как функции разрешаются компилятором? - PullRequest
2 голосов
/ 19 января 2010

Как определить, связан ли приведенный ниже вызов во время компиляции или во время выполнения?

Ответы [ 4 ]

8 голосов
/ 19 января 2010

Если метод не виртуальный, оба вызова будут разрешены во время компиляции. Если метод виртуальный, то первый вызов в вашем вопросе (obj.method()) будет разрешен во время компиляции для объекта, но во время выполнения для ссылки. Второй вызов (objp->method()) будет разрешен во время выполнения. Вы также можете заставить во время компиляции вызвать не производную версию метода.

struct base {
   void f();
   virtual void v();
};
struct derived : public base {
   void f();
   void v(); // intentionally left virtual out, it does not really matter
};
int main() {
   derived d;
   base & b = d;
   base * bp = &d;

   // compile time:
   d.f();   // derived::f
   d.v();   // derived::v
   b.f();   // base::f   -- non-virtual
   bp->f(); // base::f   -- non-virtual

   // runtime:
   b.v();   // derived::v
   bp->v(); // derived::v

   // compile time (user forced):
   b.base::v();   // base::v
   bp->base::v(); // base::v
}
2 голосов
/ 19 января 2010

В первом случае тип object известен во время компиляции (при условии, что это не ссылка). Так что это будет статическая привязка.

Во втором случае будет использоваться динамическое связывание при условии, что функция virtual. В противном случае статическая привязка.

1 голос
/ 19 января 2010

Динамическое связывание используется только в случае указателя / ссылки, а вызываемая функция является виртуальной,

object.member_fn;//if object is not reference so static binding
object.member_fn;//if object is reference and member_fn is virtual dynamic binding
p->member_fn;//p is pointer and member_fn is virtual dynamic binding

Хотя есть один случай, когда ссылка ограничивает себя временным, вызовет правильный деструктор.

#include <iostream>
using namespace std;
//virtual behavior with out the type being polymorphic
class Base
{
public: Base(){}
    ~Base(){}
};
class Derived:public Base
{
public:Derived(){}
       ~Derived(){
           std::cout<<"Destructor is not virtual, but it is called";
       }
};
void foo(){
    Base & bound_to_temporary = Derived();
}
int main(){
    foo();
    cin.get(); 
}

Выход: Деструктор не виртуален, но он называется.

1 голос
/ 19 января 2010

Я думаю, что нужно прояснить, что вызовы конструктора и деструктора в первом случае выполняются для неназванного производного объекта, это НЕ конструктор или деструктор Var.Var - это просто ссылочный тип, который не требует специальной обработки.Поскольку компилятор знает тип этого безымянного производного объекта, он корректно статически связывает их с производным классом.

Аналогично, конструктор статически связан во втором случае, потому что тип, следующий за новым, является производным.Однако, когда вы вызываете delete для указателя типа base, компилятор вызывает деструктор Base (снова со статическим связыванием).

Если вы объявили деструктор base виртуальным, тогда это окончательное связывание - то, какой деструктор вызывать при удалениипроизойдет, будет динамическим, и вы получите тот же результат, что и в первом случае.

...