c++ - 运算符重载和继承

标签 c++ operator-overloading

我得到了以下代码:

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 < 无论事件中写入什么都会被调用。

最佳答案

您一定对动态调度有点困惑。

人们常说“动态调度仅在通过指针或引用进行调用时才会发生”。从形式上来说,这种说法完全是虚假和误导性的。

当您调用虚拟函数时,C++ 中的动态分派(dispatch)总是发生,只有一个异常(exception):当您使用目标函数。例如:

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

在上面的代码中,即使 some_function 是一个虚函数,调用也会被静态调度。从语言的角度来看,没有其他方法可以避免动态分派(dispatch),即在所有其他情况下,所有对虚拟函数的调用都是动态分派(dispatch)的>。你使用什么:指针、引用、直接对象 - 没关系,调度仍然是动态的。从哪里调用函数:从构造函数/析构函数或从其他地方调用函数 - 并不重要,调度仍然是动态的。我再说一遍:从 C++ 语言本身的角度来看,事情就是这样的。这就是“抽象 C++ 机器”的工作原理。

但实际上,在许多情况下,动态分派(dispatch)可以替换为静态分派(dispatch),因为编译器在编译时提前知道对象的动态类型,因此知道对象的目标 dispatch 。在这种情况下,直接调用目标函数更有意义,而不是通过成本更高的动态调度机制。然而,这只不过是一种优化。不幸的是,有些人错误地认为对语言强制行为的优化,提出了诸如“动态调度仅在通过指针或引用进行调用时才会发生”之类的毫无意义的语句。

在您的具体情况下,调度是动态的。由于在您的情况下,编译器不知道所涉及对象的动态类型,因此无法将其优化为静态分派(dispatch),这就是您的代码“按预期工作”的原因。

附注预测关于我上面所说的内容可能存在的问题:从构造函数/析构函数进行的调用的动态调度受到对象的当前动态类型的限制,这就是为什么在简单的情况下编译器可以(并且很容易)将它们优化为静态调度。这就是另一个流行的都市传说的原因,该传说指出来自构造函数/析构函数的虚拟调用是静态解析的。实际上,在一般情况下,它们是动态解析的,正如它们应该的那样(再次观察对象的当前动态类型)。

关于c++ - 运算符重载和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3009911/

相关文章:

c++ - 同级友元运算符似乎不参与重载决议

c++ - 数组下标运算符重载

c++ - 偏导数

c++ - 如何从程序中删除日志调试语句

c++ - 无法将函数定义与模板化类中的现有定义相匹配

c++ - 重写 << 运算符无法识别

c++ - 使用非成员函数重载运算符

c++ - 其他结构内部的结构和双指针,多层混淆

c++ - 定义 "library-safe"代码的概念

c++ - Android、SWIG 和双向通信