当前位置: 首页 > news >正文

C++中不要重新定义继承而来的non-virtual函数

在 C++ 中,重定义继承而来的 non-virtual(非虚)函数通常是不推荐的,原因如下:

  1. 隐藏父类的实现:如果在派生类中重定义了一个非虚函数,这将隐藏父类中具有相同名称和参数的函数。这意味着即使通过基类的指针或引用调用该函数,也会调用派生类中的版本,这可能违反了多态性原则,导致无法调用预期的基类函数。

  2. 破坏封装:重定义非虚函数可能会导致派生类与基类之间的耦合增强,因为派生类需要知道基类的具体实现细节,并且在派生类中复制这些细节。这违反了封装的原则,使得代码难以维护和理解。

  3. 意图不明确:在派生类中重定义非虚函数可能会使类的设计意图变得不清晰。虚函数表明存在意图进行重写(override),而非虚函数通常表示不打算被重写。如果需要在派生类中提供不同的行为,应该使用虚函数。

  4. 多态行为的缺失:非虚函数不支持运行时多态,这意味着即便派生类中有与基类同名的函数,通过基类指针或引用调用该函数时,总是会调用基类的实现,而不是派生类的实现。这可能导致派生类的行为不符合预期。

  5. 维护难度增加:如果在派生类中重定义了基类的非虚函数,任何对基类函数的修改都需要在所有派生类中进行检查和相应的修改,这增加了代码的维护难度。

  6. 引起混淆:重定义基类中的非虚函数可能会使得阅读和理解代码的人员产生混淆,特别是在有多级继承时,理解哪个版本的函数被调用变得更加复杂。

如果确实需要在派生类中更改基类中某个函数的行为,应该考虑以下方案:

  • 将基类函数声明为虚函数(virtual),并在派生类中重写(override)它。
  • 如果不希望在基类中提供默认实现,可以将基类函数声明为纯虚函数(pure virtual)。
  • 如果派生类需要提供一个完全不同的函数,可以考虑给该函数取一个不同的名称,以避免与基类函数混淆。

让我们通过一个简单的例子来说明为什么不建议在派生类中重定义继承而来的 non-virtual 函数。

假设我们有一个基类 Base 和一个从 Base 继承的派生类 Derived。在基类中,我们有一个非虚拟函数 foo(),在派生类中我们重定义了这个函数。

#include <iostream>class Base {
public:void foo() {std::cout << "Base::foo()" << std::endl;}
};class Derived : public Base {
public:void foo() {std::cout << "Derived::foo()" << std::endl;}
};int main() {Base b;Derived d;// 直接调用b.foo(); // 输出: Base::foo()d.foo(); // 输出: Derived::foo()// 通过基类指针调用Base* ptr = &d;ptr->foo(); // 输出: Base::foo()return 0;
}

在上面的例子中,即使 ptr 指向的是 Derived 类型的对象,调用 ptr->foo() 时还是执行了 Base 类的 foo 方法,而不是 Derived 类的 foo 方法。这是因为 foo 被定义为非虚函数,不支持多态。

现在,假设我们想要实现多态行为,我们需要将 Base 类中的 foo() 方法声明为虚函数,并在派生类中重写它:

#include <iostream>class Base {
public:virtual void foo() {std::cout << "Base::foo()" << std::endl;}
};class Derived : public Base {
public:void foo() override { // 使用 override 关键字明确表示重写std::cout << "Derived::foo()" << std::endl;}
};int main() {Base b;Derived d;// 直接调用b.foo(); // 输出: Base::foo()d.foo(); // 输出: Derived::foo()// 通过基类指针调用Base* ptr = &d;ptr->foo(); // 输出: Derived::foo()return 0;
}

在这个修改后的例子中,由于 foo 现在是虚函数,并且在派生类中被重写,ptr->foo() 调用将执行 Derived 类的 foo 方法,展现了多态行为。

重定义可能会隐藏基类实现并导致预期外的行为,而将函数声明为虚函数并在派生类中重写可以实现正确的多态行为。

相关文章:

C++中不要重新定义继承而来的non-virtual函数

在 C 中&#xff0c;重定义继承而来的 non-virtual&#xff08;非虚&#xff09;函数通常是不推荐的&#xff0c;原因如下&#xff1a; 隐藏父类的实现&#xff1a;如果在派生类中重定义了一个非虚函数&#xff0c;这将隐藏父类中具有相同名称和参数的函数。这意味着即使通过基…...

C++ 对象型参数和返回值

对象型参数和返回值 1.对象型类型作为函数的参数2.对象型参数作为函数的返回值 1.对象型类型作为函数的参数 使用对象类型作为函数的参数或者返回值&#xff0c;可能会产生一些不必要的中间对象 例子&#xff1a; // 使用对象类型作为函数的参数 void test1(Car car) {}完整代…...

LeetCode 字符串专题——KMP算法_28. 找出字符串中第一个匹配项的下标

字符串专题——KMP算法 KMP算法例题 KMP算法 待更新 例题 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/ class Solution {vector<int> next;void getNext(string s){int j-1;next[0]-1;int lens.size();for(int i…...

上班不想用脑子写代码了怎么办?那就试试Baidu Comate啊宝贝

本文目录 前言1、视频编程实战1.1、熟悉代码库中的代码1.2、参考现有代码编写新代码 2、下载使用教程3、使用体验3.1、AutoWork 产品测评3.2、解决有关ajax请求后重定向问题3.3、询问编程相关知识3.3.1、cookie和session的区别与联系3.3.2、数据库中主键外键的相关知识 4、问题…...

【管理咨询宝藏94】某国际咨询公司供应链财务数字化转型方案

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏94】某国际咨询公司供应链&财务数字化转型方案 【格式】PDF版本 【关键词】国际咨询公司、制造型企业转型、数字化转型 【核心观点】 - 172…...

C++_使用邻接表(链表-指针)实现有向图[完整示例及解释]

这个程序是一个图的实现&#xff0c;使用邻接表来表示图的结构&#xff1a; 1. 结构定义部分&#xff1a; - AdjListNode 结构定义了邻接表中的节点&#xff0c;每个节点包含一个名称和一个指向下一个邻接节点的指针。 - Node 结构定义了图中的节点&#xff0c;每个节点…...

Gitlab自动化测试的配置

1. 代码分支命名规范检测 Setting → Repository → Push rules → Branch name&#xff0c;添加分支命名规范对应的正则表达式。如&#xff1a; ^(Release|Tag|Develop|Feature)_._.|Main$ 表示分支名只能以以下关键字之一开头&#xff1a;Release、Tag、Develop和Feature。 …...

Qwen-Audio:推动通用音频理解的统一大规模音频-语言模型(开源)

随着人工智能技术的不断进步&#xff0c;音频语言模型&#xff08;Audio-Language Models&#xff09;在人机交互领域变得越来越重要。然而&#xff0c;由于缺乏能够处理多样化音频类型和任务的预训练模型&#xff0c;该领域的进展受到了限制。为了克服这一挑战&#xff0c;研究…...

杭州破冰之举:全面取消住房限购,激发市场新活力

在房地产市场调控的浪潮中,杭州再次走在了前列,于2024年3月14日宣布全面取消二手房限购政策,此举在行业内引发了广泛关注。作为中国经济活力较强的二线城市之一,杭州的这一决策不仅体现了地方政府在房地产市场调控上的灵活应变,也释放出对市场流动性和经济发展的积极信号。…...

ICode国际青少年编程竞赛- Python-1级训练场-变量练习

ICode国际青少年编程竞赛- Python-1级训练场-变量练习 1、 a 8 for i in range(8):Dev.step(a)Dev.turnRight()a - 12、 a 3 for i in range(4):Dev.step(a)Dev.turnRight()a a 1 Dev.step(5)3、 a 4 for i in range(4):Dev.step(2)Dev.step(-5)Dev.step(3)Spaceship.…...

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz&#xff0c;当板载8MHz晶振时&#xff0c;系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​&#xff0c;在文件stm32f4xx.h中可修…...

智能BI(后端)-- 系统异步化

文章目录 系统问题分析什么是异步化&#xff1f;业务流程分析标准异步化的业务流程系统业务流程 线程池为什么需要线程池&#xff1f;线程池两种实现方式线程池的参数线程池的开发 项目异步化改造 系统问题分析 问题场景&#xff1a;调用的服务能力有限&#xff0c;或者接口的…...

AI绘画Stable Diffusion 插件篇:智能标签提示词插件sd-danbooru-tags-upsampler

大家好&#xff0c;我是向阳。 关于智能标签提示词插件&#xff0c;在很早之前就介绍过很多款了&#xff0c;今天再给大家介绍一款智能标签提示词插件sd-danbooru-tags-upsampler。该智能提示词插件是今年2月23号才发布的第一版V0.1.0&#xff0c;算是比较新的智能提示词插件。…...

Android OpenMAX(六)OMXStore

在前面两节的学习中我们知道了OMX Core是用来管理(查询/创建/销毁)Android平台上的硬件编解码组件的。这一节我们再向上一层,Android平台除了提供有硬件编解码组件支持,还内置了一些软件编解码组件,为了统一管理所有(软/硬)编解码组件,Android在OMX Core之上又抽象了一…...

Ubuntu下halcon软件的下载安装

由于工作需求&#xff0c;点云配准需要使用halcon进行实现&#xff0c;并且将该功能放入QT界面中 1.下载halcon 进入halcon官网进行下载 官网链接&#xff1a;https://www.mvtec.com/products/halcon/ 注意&#xff1a;要注册登陆之后才能进行下载 接着点击Downloads->H…...

『ZJUBCA Collaboration』WTF Academy 赞助支持

非常荣幸宣布&#xff0c;浙江大学区块链协会收到WTF Academy的赞助与支持&#xff0c;未来将共同开展更多深度合作。 WTF Academy是开发者的Web3开源大学&#xff0c;旨在通过开源教育让100,000名开发者进入到Web3。截止目前&#xff0c;WTF开源教程在GitHub收获超15,000 ⭐&a…...

Python开源工具库使用之运动姿势追踪库mediapipe

文章目录 前言一、姿势估计1.1 姿态关键点1.2 旧版 solution API1.3 新版 solution API1.4 俯卧撑计数 二、手部追踪2.1 手部姿态2.2 API 使用2.3 识别手势含义 参考 前言 Mediapipe 是谷歌出品的一种开源框架&#xff0c;旨在为开发者提供一种简单而强大的工具&#xff0c;用…...

【Android Studio】开启真机调试

1 打开手机的开发者模式 各种款式的手机进入开发者模式的情况不同&#xff0c;但大致是在 【关于手机】中多次点击系统版本即可进入。这里以小米8为例&#xff0c;记录下流程。 1.1 进入手机开发者模式 【设置】->【我的设备】->【全部参数】->【MIUI版本】连续点击3…...

CMakeLists.txt语法规则:部分常用命令说明四

一. 简介 前面几篇文章学习了CMakeLists.txt语法中前面几篇文章学习了CMakeLists.txt语法中部分常用命令。文章如下&#xff1a; CMakeLists.txt语法规则&#xff1a;部分常用命令说明一-CSDN博客 CMakeLists.txt语法规则&#xff1a;部分常用命令说明二-CSDN博客 CMakeLi…...

学习前端第三十二天(Rest 参数与 Spread 语法,变量作用域,闭包)

一、Rest 参数与 Spread 语法 1.rest参数 ...变量名&#xff1a;收集剩余的参数并存进指定数组中&#xff0c;需要放到最后&#xff1b; 2.arguments变量 // arguments,以参数在参数列表中的索引作为键&#xff0c;存储所有参数,以类数组对象的形式输出所有函数参数 // 箭头…...

LFM2.5-1.2B-Thinking-GGUF入门指南:Python零基础调用与第一个AI应用

LFM2.5-1.2B-Thinking-GGUF入门指南&#xff1a;Python零基础调用与第一个AI应用 1. 前言&#xff1a;为什么选择这个模型&#xff1f; 如果你刚接触AI大模型&#xff0c;可能会被各种复杂的术语和配置吓到。LFM2.5-1.2B-Thinking-GGUF是个不错的选择——它体积适中但能力不俗…...

RexUniNLU框架应用案例:SpringBoot集成实现教育平台客服智能意图识别

RexUniNLU框架应用案例&#xff1a;SpringBoot集成实现教育平台客服智能意图识别 1. 教育客服场景的智能化挑战 在线教育平台的客服系统每天需要处理大量用户咨询&#xff0c;从"我的课程怎么打不开"到"想了解编程课的价格"&#xff0c;这些看似简单的提…...

状态方程离散化

基于二阶RC卡尔曼滤波EKF的锂电池SOC估计仿真 仿真数据&#xff1a;HPPC工况&#xff0c;模型中自带数据 附带卡尔曼滤波EKF算法说明文档 图1&#xff1a;真实值与估计值对比曲线 图2&#xff1a;误差率波形 图3&#xff1a;估算SOC锂电池的荷电状态&#xff08;SOC&#xff09…...

乙巳马年·皇城大门春联生成终端W与低代码平台集成:在Dify中快速创建AI应用

乙巳马年皇城大门春联生成终端W与低代码平台集成&#xff1a;在Dify中快速创建AI应用 又到了岁末年初&#xff0c;很多朋友、商家甚至社区都在为准备春联发愁。传统方式要么自己写&#xff0c;要么找人设计&#xff0c;费时费力不说&#xff0c;风格还未必满意。现在&#xff…...

开源大模型部署新范式:像素幻梦Streamlit前端+diffusers后端架构解析

开源大模型部署新范式&#xff1a;像素幻梦Streamlit前端diffusers后端架构解析 1. 项目概览 像素幻梦(Pixel Dream Workshop)是一款基于FLUX.1-dev扩散模型的像素艺术生成工具&#xff0c;它重新定义了AI艺术创作的用户体验。与传统AI绘图工具不同&#xff0c;它采用了独特的…...

告别Activity重建:用onConfigurationChanged优雅处理Android 13+的深色主题与多语言切换

告别Activity重建&#xff1a;用onConfigurationChanged优雅处理Android 13的深色主题与多语言切换 在Android 13及更高版本中&#xff0c;深色主题动态切换和多语言即时切换已成为提升用户体验的关键功能。传统方案通过重建Activity实现配置变更&#xff0c;但会导致界面闪烁、…...

Spring Cloud Hystrix 详细示-元一软件

Hystrix 是 Spring Cloud 中实现服务熔断、降级、隔离的核心组件&#xff0c;用于解决微服务架构中的雪崩效应&#xff0c;核心是快速失败、优雅降级、自动恢复。以下从环境搭建、基础使用、高级配置、Feign 整合、监控5 个维度提供完整示例。一、项目环境准备1. 依赖引入&…...

bb_imu:嵌入式多IMU统一驱动库与自动识别方案

1. 项目概述bb_imu是由 BitBank Software, Inc. 开发并维护的嵌入式惯性测量单元&#xff08;IMU&#xff09;统一驱动库&#xff0c;专为资源受限的微控制器平台&#xff08;如基于 ARM Cortex-M 系列的 STM32、ESP32、nRF52&#xff0c;以及 Arduino AVR 架构&#xff09;设计…...

Linux新手必看:Deepin、Mint、Fedora等主流发行版安装镜像获取全攻略

Linux新手必看&#xff1a;Deepin、Mint、Fedora等主流发行版安装镜像获取全攻略 当你第一次踏入Linux世界的大门&#xff0c;面对众多发行版的选择&#xff0c;获取正确的安装镜像往往是第一步。就像选择一把合适的钥匙&#xff0c;镜像的质量和来源直接关系到系统安装的成败。…...

从‘量子电子商务’到三方协议:手把手拆解量子数字签名(QDS)的核心流程与实验挑战

量子数字签名&#xff1a;从理论到实验的技术深潜与挑战解析 量子数字签名&#xff08;QDS&#xff09;作为后量子密码学的重要分支&#xff0c;正在从实验室走向实际应用。不同于传统数字签名依赖数学难题的复杂性&#xff0c;QDS基于量子力学的基本原理&#xff0c;为信息安全…...