перегрузка и наследование операторов - PullRequest
2 голосов
/ 10 июня 2010

мне дали следующий код:

class FibHeapNode
{
     //...

     // These all have trivial implementation
     virtual void operator =(FibHeapNode& RHS);
     virtual int  operator ==(FibHeapNode& RHS);
     virtual int  operator <(FibHeapNode& RHS);

};

class Event : public FibHeapNode
{
     // These have nontrivial implementation
     virtual void operator=(FibHeapNode& RHS);
     virtual int operator==(FibHeapNode& RHS);
     virtual int operator<(FibHeapNode& RHS);

};

class FibHeap
{
     //...

     int  DecreaseKey(FibHeapNode *theNode, FibHeapNode& NewKey)
     {
          FibHeapNode *theParent;

          // Some code

          if (theParent != NULL && *theNode < *theParent)
          {
            //...
          }

          //...
          return 1;
     }
};

Большая часть реализации FibHeap похожа: указатели FibHeapNode разыменовываются, а затем сравниваются.

Почему этот код работает? (или это глючит?) Я думаю, что virtual здесь не будет иметь никакого эффекта: поскольку * theNode и * theParent не являются указателями или ссылочными типами, динамическая диспетчеризация не происходит, и FibHeapNode :: operator <вызывается независимо от того, что написано в Event. </p>

Ответы [ 2 ]

5 голосов
/ 10 июня 2010

Вы должны быть немного озадачены динамической отправкой.

Часто говорят, что "динамическая отправка происходит только тогда, когда вы делаете вызов через указатель или через ссылку". Формально это утверждение является полностью ложным и вводящим в заблуждение.

Динамическая диспетчеризация в C ++ происходит всегда при вызове виртуальной функции, с одним и единственным исключением: динамическая диспетчеризация отключается, когда вы используете полностью определенное имя цели функция. Например:

some_pointer->SomeClass::some_function(); // fully-qualified name

В приведенном выше коде вызов будет отправляться статически, даже если some_function является виртуальной функцией. С языковой точки зрения, есть нет других способов избежать динамической отправки, т. Е. В во всех других случаях все вызовы виртуальных функций отправляются динамически . Что вы используете: указатель, ссылка, непосредственный объект - не имеет значения, отправка по-прежнему динамическая . Откуда вы вызываете функцию: из конструктора / деструктора или откуда-то еще - не имеет значения, отправка по-прежнему динамическая . И я повторяю: так обстоит дело с точки зрения самого языка C ++. Вот как работает «абстрактная машина C ++».

Однако на практике происходит то, что во многих случаях динамическая диспетчеризация может быть заменена статической диспетчеризацией, поскольку компилятор заранее знает динамический тип объекта во время компиляции и, следовательно, знает цель отправка. В таких случаях имеет смысл вызывать целевую функцию напрямую, а не использовать более дорогой механизм динамической отправки. Тем не менее, это не что иное, как оптимизация. К сожалению, некоторые люди ошибочно принимают за оптимизацию поведения, предписанного языком, предлагая такие бессмысленные выражения, как «динамическая диспетчеризация происходит только тогда, когда вы делаете вызов через указатель или ссылку».

В вашем конкретном случае отправка является динамической. Поскольку в вашем случае компилятор не знает динамические типы задействованных объектов, он не может оптимизировать его в статическую диспетчеризацию, поэтому ваш код «работает как задумано».

P.S. Предвосхищая возможные вопросы о чем-то, что я сказал выше: Динамическая диспетчеризация для вызовов, сделанных из конструкторов / деструкторов, ограничена текущим динамическим типом объекта, поэтому в простых случаях компилятор может (и легко) оптимизировать их в статическая отправка. Это причина другой популярной городской легенды, которая утверждает, что виртуальные вызовы от конструкторов / деструкторов разрешаются статически. В действительности, в общем случае они разрешаются динамически, как и должны (опять же, наблюдая за текущим динамическим типом объекта).

1 голос
/ 10 июня 2010

* theNode и * theParent являются ссылочными типами.Infact FibHeapNode & ref очень эквивалентен * theNode.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...