标准的动态类型定义与“多态”无关,非多态对象同样会出现动态类型不同于静态类型的情形

C++ 标准在讨论 glvalue 时,经常会看到类似说法:

If a glvalue refers to a polymorphic object, its dynamic type may differ from its static type.

中文:

如果一个 glvalue 指代一个多态对象,它的动态类型可能不同于它的静态类型。

,这样说, 这句话作为"提醒存在这种情形"是对的,但它不是标准原文,而且把一个非必要条件写成了条件句,会误导。

标准的动态类型定义与"多态"无关,非多态对象同样会出现动态类型不同于静态类型的情形。

标准原文

动态类型的正式定义在 defns.dynamic.type,原文是:

⟨glvalue⟩ type of the most derived object to which the glvalue refers

配的例子是:若 p 是 "pointer to class B" 且指向 B 的基类子对象,而该子对象的最派生对象是 D,则 *p 的动态类型是 "D",并补一句 "References are treated similarly."

关键在于:这个条目通篇没有出现 "polymorphic" 或 "virtual"。定义的谓语只依赖"glvalue 所指示对象的最派生对象",不依赖多态性。

静态类型在 defns.static.type:

type of an expression resulting from analysis of the program without considering execution semantics

它只由程序形式决定,运行期不变。而多态类的定义在 class.virtual/1:

A class with a virtual member function is called a polymorphic class.

多态不是必要条件

cpp 复制代码
struct B {};        // 非多态
struct D : B {};    // 非多态

D d;
B* p = &d;
// *p: 静态类型 B, 动态类型 D

*p 是 glvalue,指代 d 的 B 基类子对象;该子对象的 most derived object 是 d,类型 D。于是 D ≠ B,而 B 没有任何虚函数。

反过来说,"多态"也不是充分刻画动态类型的工具,它只是说明能否在运行期观测或使用动态类型。

"多态"真正起作用的地方

  • typeid :按 expr.typeid,只有当操作数是多态类类型的 glvalue 时,结果才表示最派生对象的类型(即动态类型);否则一律表示表达式的静态类型。
  • dynamic_cast :向下/交叉转换按 expr.dynamic.cast/5 要求操作数是多态类型的指针或 glvalue,否则编译错误;向上转换(/4)在编译期解析,不需要多态。
  • 虚函数分派:只有多态类才有虚表,因而只有它的运行期行为依赖动态类型。

更准确的说法

cppreference 的原话(Value categories):

A glvalue may be polymorphic: the dynamic type of the object it identifies is not necessarily the static type of the expression.

翻译过来是:glvalue 可以是多态的,即它所标识对象的动态类型未必是表达式的静态类型。对应的反面陈述是 prvalue 不可能是多态的,其动态类型恒等于表达式的类型。

所以如果你要写定义,应说:

任何 glvalue 都有动态类型,即其所指代对象的最派生对象的类型,它可以不同于表达式的静态类型

而不是把"多态"设为前提。

Sources

相关推荐
冬、不眠的夜1 小时前
Nuitka 将 python 程序编译成 exe 指南
开发语言·python
CVer儿1 小时前
起源1引擎相关知识点2--World Brush+func_detail
开发语言
MOONICK1 小时前
COM 组件技术(三)
c++·windows
_wxd6661 小时前
二叉搜索树(BST)万字详解:概念、操作、性能分析与 C++ 实现
数据结构·c++·二叉搜索树
薛之谦_1 小时前
JAVA 多线程编程:从基础原理到实战应用
java·开发语言
LMT_Lanmantech1 小时前
Creo许可降本增效:不增购,也能让现有许可发挥更大价值
java·大数据·开发语言
UIU1142 小时前
P1115 最大子段和
c++·算法
wuminyu2 小时前
ZGC染色指针在虚拟线程stackChunkOop上的并发屏障全景分析
java·linux·c语言·jvm·c++
蜗牛互联网2 小时前
Python Agent 工具调用:审批令牌、参数白名单和累计预算
java·开发语言·人工智能·windows·后端·python