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

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

相关推荐
1024奇点8 小时前
【仓颉语言入门 · 第二篇 第 22 课】
开发语言·ide·开源
Warren2Lynch9 小时前
C4 模型详解:利用 Visual Paradigm 可视化软件架构的综合指南
开发语言·uml
FlightYe9 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
Knight_AL9 小时前
Java 文件下载时文件名中的 `#` 被转换成 `%23`?一次 URL 编码与解码问题排查
java·开发语言
FRing0310 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
by2099910 小时前
C++ 智能指针的所有权与使用
开发语言·c++·经验分享
砚底藏山河10 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
IT召唤狮11 小时前
开源企业级零信任项目Pangolin,零信任能挡住PHP核弹漏洞吗?
开发语言·开源·php
知已难寻11 小时前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件
Rover Ramble11 小时前
C++ 用互斥锁实现读写锁
开发语言·c++