0

0

C++中的虚函数重写规则是什么?(为什么返回类型可以是协变返回类型)

尼克

尼克

发布时间:2026-02-12 19:27:11

|

969人浏览过

|

来源于php中文网

原创

虚函数重写必须函数名、参数类型列表、const/volatile限定符、ref-qualifier完全一致;返回类型仅允许协变,即base→derived或base&→derived&,且derived须公有继承自base。

c++中的虚函数重写规则是什么?(为什么返回类型可以是协变返回类型)

虚函数重写必须满足哪些签名条件

重写(override)不是“名字一样就行”,C++ 要求 函数名参数类型列表const/volatile 限定符ref-qualifier(& 或 &&) 必须完全一致,否则编译器当它是新函数(重载),不是重写。返回类型是唯一允许“不完全相同”的地方——但仅限协变返回类型。

常见错误现象:Base* 返回却在派生类里写成 Derived*,但没用指针/引用;或返回 std::unique_ptr<base> 却想重写为 std::unique_ptr<derived></derived> —— 这些都不协变,直接报错 error: 'func' does not override any member function

  • 协变只适用于指针和引用类型:比如 Base*Derived*,或 Base&Derived&,且 Derived 必须公有继承自 Base
  • 返回类型不能是值类型(如 BaseDerived)、也不能是智能指针、容器、函数类型等——它们不满足“可安全转换 + 地址兼容”要求
  • 参数列表哪怕差一个 const(比如 void f(int) vs void f(const int)),就不算重写(因为顶层 const 不影响类型)

为什么只允许指针/引用类型协变

根本原因是对象布局和多态调用的安全性。虚函数调用时,编译器生成的代码依赖基类接口约定的返回值大小、内存对齐、析构行为。指针/引用的大小和调用约定在继承体系中是统一的(都是 8 字节、都支持多态析构),而值类型会触发复制、可能调用派生类析构函数去清理基类对象,破坏 ABI 稳定性。

举个典型场景:你写 virtual Base* clone() const,派生类实现 Derived* clone() const。用户用 Base* p = obj.clone(),实际拿到的是 Derived*,但能安全赋给 Base*,且后续通过 p->some_virtual_func() 仍能正确分发到 Derived 版本——这正是协变设计要保的契约。

立即学习C++免费学习笔记(深入)”;

狸谱App
狸谱App

AI壁纸漫画梗图,年轻人的抽象创作社区

下载
  • 协变返回类型在 ABI 层面没有额外开销:返回寄存器(如 %rax)传的仍是地址,无需调整
  • 如果允许 BaseDerived 值返回,就涉及对象切片或隐式构造,无法保证虚表指针被正确设置
  • std::shared_ptr<base> 看似“像指针”,但它不是语言内置的协变类型,C++ 标准没为此特设规则,所以不能协变

override 关键字怎么帮你看穿重写失败

不加 override,编译器不会主动检查是否真构成了重写;加了,它就会严格比对基类虚函数签名,稍有不符立刻报错。这是防止“以为重写了结果只是新增了一个重载函数”的最有效手段。

常见错误现象:基类函数是 virtual void f(int&) const,派生类写成 void f(const int&) const override —— 参数类型不一致,override 直接让编译失败,而不是静默接受。

  • 永远在你“打算重写”的函数声明末尾加上 override,别省
  • 如果加了 override 却编译不过,说明签名没对齐:逐项核对 const&、参数类型(注意 intint& 是不同类型)、函数名拼写
  • 基类函数没声明 virtual?那加 override 也会报错——这是提醒你:它根本不是虚函数,重写无意义

协变返回类型在模板类里能不能用

能,但受限于模板实例化时机。只要模板参数能推导出明确的继承关系,协变就生效;但如果继承关系依赖未确定的模板参数(比如 T 是否继承自 U 尚未可知),编译器无法验证协变合法性,就会拒绝。

使用场景:写泛型工厂或克隆接口时,比如 template<typename t> struct Clonable { virtual T* clone() const = 0; };</typename>,派生类 struct D : Clonable<d> { D* clone() const override; }</d> 是合法的,因为 D 显式作为模板实参,继承关系明确。

  • 别试图在模板中写 virtual Base<t>* f()</t>Derived<t>* f() override</t>,除非你能保证 Derived<t></t> 公有继承自 Base<t></t>,且该关系在实例化点可见
  • 协变不跨模板实例:Base<int>*</int>Base<double>*</double> 之间不存在协变关系,哪怕它们都叫 Base
  • 如果编译器报 error: covariant return type must be a class type derived from ...,大概率是模板推导出了非类类型,或继承关系未被正确定义(比如用了私有继承)

协变看着宽松,其实每条限制都在堵住二进制层面的漏洞。最容易被忽略的是:它只认语言原生的指针/引用语义,不买任何封装类型的账——哪怕那个封装类型行为上“几乎就是指针”。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

20

2025.11.27

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

351

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

326

2023.10.25

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

542

2023.09.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

708

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

560

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

193

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

206

2025.08.29

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

4

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.3万人学习

C 教程
C 教程

共75课时 | 4.7万人学习

C++教程
C++教程

共115课时 | 17.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号