c++ - 为什么取消引用运算符在 C++ 中保留多态性(后期绑定(bind))?

标签 c++ polymorphism

众所周知,“仅当调用是通过 引用或指针。”。因此,当我发现解引用运算符也保留了动态绑定(bind)特性时,我感到很惊讶。

#include <iostream>
using namespace std;

struct B {
  virtual void say() { cout << "Hello B" << endl; }
};

struct D : B {
  void say() override { cout << "Hello D" << endl; }
};

int main() {
    D *ptr = new D();
    B *p = ptr;
    (*p).say();
    return 0;
}

输出是

Hello D

问题:编译器如何处理取消引用运算符 *?

我以为是在编译时完成的。因此,当编译器引用指针 p 时,它应该假定 p 指向 B 类型的对象。例如,以下代码

D temp = (*p);

提示

error: no viable conversion from 'B' to 'D'

最佳答案

从表面上看,这是一个有趣的问题,因为没有一元 * 的重载,取消引用会导致 lvalue B ,不是引用类型。然而,即使开始沿着这条推理线走下去也是一个转移注意力的问题:表达式从不 有引用类型,因为引用会立即被删除并确定值类别。从这个意义上说,一元 * 运算符非常像一个返回引用的函数

事实上,答案是您最初的断言是不正确的:动态调度根本不依赖于引用或指针。是引用和指针使您能够防止切片,但是一旦您有一些引用多态对象的表达式,任何旧的函数调用都可以。

还要考虑:

#include <iostream>

struct Base
{
   virtual void foo() { std::cout << "Base::foo()\n"; }
   void bar() { foo(); }
};

struct Derived : Base
{
   virtual void foo() { std::cout << "Derived::foo()\n"; }
};

int main()
{
   Derived d;
   d.bar();    // output: "Derived::foo()"
}

( live demo )

关于c++ - 为什么取消引用运算符在 C++ 中保留多态性(后期绑定(bind))?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23748057/

相关文章:

Java:使函数不是虚拟的-在父引用上调用父方法

java - 如何像使用接口(interface)一样使用枚举?

c++ - 在目录中的文件子集上构建 visual studio 项目

c++ - 试图反转一个字符串

c++ - C++标准库中有算术类型的概念吗?

java - 如何防止接口(interface)出现冗余代码

c++ - 在 C++ 中在堆栈上创建实例时如何保持多态性?

polymorphism - OCaml 中的空树类型

c++ - 我的 gloox 机器人有误

c++ - 用 while 循环替换 for 循环