c++多态机制

news2025/4/25 23:39:25

多态

在 C++ 中,多态(Polymorphism)是一种面向对象编程的重要概念,它允许不同类的对象对同一消息做出不同的响应。具体来说,多态性允许基类的指针或引用在运行时指向派生类的对象,并且根据对象的实际类型来调用相应的成员函数。
多态性是通过虚函数来实现的。当一个基类的成员函数被声明为虚函数时,派生类可以通过覆盖(重写)这个函数来提供自己的实现。在运行时,调用这个虚函数的时候,实际上调用的是指向对象的实际类型的版本。
C++ 中的多态性有两种形式:静态多态(编译时多态)和动态多态(运行时多态)。
1.静态多态(编译时多态): 主要是通过函数重载和模板实现的,例如,同一个函数名可以有多个版本,根据参数的类型和数量来决定调用哪个版本的函数。这种多态性在编译时就已经确定了。
2.动态多态(运行时多态): 主要是通过虚函数和继承实现的,例如,基类指针指向派生类对象,并调用虚函数。在运行时,根据对象的实际类型来决定调用哪个版本的函数。这种多态性在运行时才会确定。

静态多态

静态多态(也称为编译时多态或早期多态)是指在编译时就确定函数调用的方式,主要通过函数重载和模板来实现。在静态多态中,编译器在编译时根据函数的签名(函数名称和参数列表)来确定调用哪个函数版本。
静态多态主要有两种形式:
1.函数重载: 函数重载允许在同一作用域内声明多个函数,它们具有相同的名称但参数列表不同。在调用函数时,编译器根据传递的参数的数量、类型和顺序来选择匹配的函数。

#include <iostream>

// 函数重载示例
void print(int x) {
    std::cout << "Integer: " << x << std::endl;
}

void print(double x) {
    std::cout << "Double: " << x << std::endl;
}

int main() {
    print(5);       // 调用第一个 print 函数
    print(3.14);    // 调用第二个 print 函数
    return 0;
}

2.模板: 模板是一种通用编程技术,允许编写与特定类型无关的代码。通过使用模板,可以在不同类型的参数上执行相同的操作,而无需为每种类型编写不同的函数。

#include <iostream>

// 模板示例
template <typename T>
void print(T x) {
    std::cout << "Value: " << x << std::endl;
}

int main() {
    print(5);           // 实例化一个 int 类型的 print 函数
    print(3.14);        // 实例化一个 double 类型的 print 函数
    print("Hello");     // 实例化一个 const char* 类型的 print 函数
    return 0;
}

在这里插入图片描述

在静态多态中,函数调用的决定在编译时完成,因此性能更高。然而,静态多态的缺点是在编写代码时必须明确指定每个函数的具体版本,如果有大量的重载或模板,可能会导致代码量增加和可读性降低。

动态多态

动态多态(也称为运行时多态或晚期多态)是指在程序运行时根据对象的实际类型来决定调用哪个函数版本。动态多态性通过虚函数和继承来实现,在编译时无法确定函数调用的具体版本,而是在运行时根据对象的类型动态确定。
动态多态的实现需要满足以下两个条件:
1.基类中声明虚函数:在基类中将函数声明为虚函数,这样编译器就会在运行时进行函数调用的动态绑定。
2.派生类重写虚函数:派生类中可以通过重写(覆盖)基类中的虚函数来提供自己的实现。在调用这个虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。
下面是一个简单的示例,演示了动态多态的用法:

#include <iostream>

// 基类
class Animal {
public:
    // 虚函数
    virtual void makeSound() {
        std::cout << "Animal makes a sound" << std::endl;
    }
};

// 派生类
class Dog : public Animal {
public:
    // 重写基类的虚函数
    void makeSound() override {
        std::cout << "Dog dog" << std::endl;
    }
};

// 派生类
class Cat : public Animal {
public:
    // 重写基类的虚函数
    void makeSound() override {
        std::cout << "Cat cat" << std::endl;
    }
};

int main() {
    // 创建派生类对象
    Dog dog;
    Cat cat;

    // 基类指针指向派生类对象
    Animal* ptr1 = &dog;
    Animal* ptr2 = &cat;

    // 通过基类指针调用虚函数,实现多态
    ptr1->makeSound(); // 调用的是派生类 Dog 的 makeSound() 函数
    ptr2->makeSound(); // 调用的是派生类 Cat 的 makeSound() 函数

    return 0;
}

Animal 类有一个虚函数 makeSound(),而 Dog 和 Cat 类分别继承自 Animal 类并重写了 makeSound() 函数。在 main() 函数中,我们创建了 Dog 和 Cat 类的对象,并将基类指针指向这些对象,然后通过基类指针调用虚函数 makeSound()。由于 makeSound() 是虚函数,所以在运行时根据对象的实际类型来决定调用哪个版本的函数,从而实现了动态多态性。

父类指针指向子类对象

在 C++ 中,可以使用父类的指针来指向子类的对象,这是实现多态的一种常见方式。这种行为被称为向上转型(upcasting),它允许您通过基类的接口来操作派生类的对象。这在面向对象编程中是非常有用的,因为它使代码更加灵活和可扩展。
下面是一个简单的示例说明了如何使用父类的指针来指向子类的对象:

#include <iostream>

// 基类
class Base {
public:
    virtual void display() {
        std::cout << "Base class display() called" << std::endl;
    }
};

// 派生类
class Derived : public Base {
public:
    void display() override {
        std::cout << "Derived class display() called" << std::endl;
    }
};

int main() {
    // 创建派生类对象
    Derived derivedObj;

    // 使用基类指针指向派生类对象
    Base* basePtr = &derivedObj;

    // 通过基类指针调用虚函数,实现多态
    basePtr->display(); // 调用的是派生类的 display() 函数

    return 0;
}

Base 是基类,Derived 是派生类。Base 类有一个虚函数 display(),Derived 类重写了 display() 函数。在 main() 函数中,我们创建了 Derived 类的对象 derivedObj,然后使用 Base 类的指针 basePtr 指向了 derivedObj。最后,通过 basePtr 调用 display() 函数,由于 display() 函数是虚函数,所以调用的是 Derived 类中的版本,实现了多态行为。

方法调用

在 C++ 中,如果父类通过指针或引用调用一个虚函数,而这个虚函数在子类中被重写(override),那么调用的实际方法将取决于指针或引用所指向的对象的类型。这就是多态的体现。
具体来说,如果父类指针或引用指向的是子类对象,那么调用的方法将是子类中重写的版本;如果指针或引用指向的是父类对象,那么调用的方法将是父类中的版本。
下面是一个示例来说明这一点:

#include <iostream>

// 基类
class Base {
public:
    virtual void show() {
        std::cout << "Base class show()" << std::endl;
    }
};

// 派生类
class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class show()" << std::endl;
    }
};

int main() {
    // 创建派生类对象
    Derived derivedObj;

    // 使用基类指针指向派生类对象
    Base* basePtr = &derivedObj;

    // 通过基类指针调用虚函数,实现多态
    basePtr->show(); // 调用的是派生类的 show() 函数

    return 0;
}

Base 类是基类,Derived 类是派生类。在 main() 函数中,我们创建了 Derived 类的对象 derivedObj,然后使用 Base 类的指针 basePtr 指向了 derivedObj。最后,通过 basePtr->show() 调用 show() 函数,由于 show() 是虚函数,因此调用的是 Derived 类中的版本,而不是 Base 类中的版本。

2024年5月11日21:04:05
疏影斜横水清浅,暗香浮动月黄昏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1664627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

汇昌联信科技:做拼多多网店要押金吗?

做拼多多网店要押金吗?”这个问题&#xff0c;其实与拼多多的平台规则有关。在开店之前&#xff0c;商家需要详细了解平台的各项规定和费用构成&#xff0c;这样才能做好充足的准备。 一、明确回答问题 做拼多多网店&#xff0c;不需要支付押金。拼多多的入驻门槛相对较低&…

烽火三十六技丨网络资产安全治理平台新版本发布,一文看懂四大核心优势

云计算、移动互联网、物联网等技术飞速发展&#xff0c;网络环境愈发开放互联&#xff0c;原有的资产管理方式已难以适应当下的变化。同时&#xff0c;网络资产需求的突发性和人为疏忽&#xff0c;也时常导致资产数量不明、类型模糊、安全漏洞检查不全面等问题。因此&#xff0…

增加表空间的数据文件

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 表空间创建完成后&#xff0c;后期还可以为表空间增加数据文件&#xff0c;以扩大数据的存储空间。增加表空间数据文件的基本语法结构如下所示。 ALTER TABLESPACE 表空间名…

SpringCloud:服务拆分和远程调用

程序员老茶 &#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; P   S : 点赞是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#…

详解drop,delete,truncate区别

在SQL中&#xff0c;"DROP"、"DELETE"和"TRUNCATE"是用于删除数据的不同命令&#xff0c;它们之间有一些重要的区别&#xff1a; DROP&#xff1a; DROP用于删除数据库对象&#xff0c;例如删除表、视图、索引、触发器等。使用DROP删除的对象将…

如何撰写一份优秀的产品需求文档?看完真的不用加班了!

产品需求文档&#xff08;PRD&#xff09;是产品经理最主要的可视化交付物&#xff0c;刚入门的产品会疑惑产品需求文档应该如何撰写&#xff0c;产品老鸟们也会头痛产品文档如何高效更新和维护。本文会详细介绍2024年最新的极简产品文档撰写和管理方案&#xff0c;建议阅读并收…

数据库被攻击后出现1044 - access denied for user ‘root‘@‘% ‘ to database table

MySQL数据库被攻击后&#xff0c;数据库全部被删除&#xff0c;并且加一个一个勒索的数据&#xff0c;向我索要btc&#xff0c; 出现这个问题就是我的数据库密码太简单了&#xff0c;弱密码&#xff0c;被破解了&#xff0c;并且把我权限也给修改了 导致我操作数据库时&#…

【大数据·hadoop】在hdfs上运行shell基本常用命令

一、准备工作 1.1格式化并启动Hadoop服务 参见Hadoop在ubuntu虚拟机上的伪分布式部署|保姆级教程的4.7节 二、HDFS常用命令 接着&#xff0c;就愉快地在刚刚的命令行里敲命令啦 1.显示hdfs目录结构 hadoop fs -ls -R /hadoop fs: 这是Hadoop文件系统命令行的一部分&#x…

ICode国际青少年编程竞赛- Python-4级训练场-综合训练4

ICode国际青少年编程竞赛- Python-4级训练场-综合训练4 1、 Dev.turnLeft() Dev.step(3) Dev.turnRight() Dev.step(3) Dev.turnLeft() Dev.step(4)2、 for i in range(3):Dev.step(2)Dev.turnRight()while Flyer[i].disappear():wait()Dev.step(2 i)Dev.turnLeft()3、 …

【linux僵尸进程查看与删除】

linux僵尸进程查看与删除 linux僵尸进程查看linux僵尸进程停止方法僵尸进程产生原因僵尸进程的危害 linux僵尸进程查看 使用top 命令查看&#xff0c;发现有13 zombie&#xff0c;即13个僵尸进程。 linux僵尸进程停止方法 使用ps -ef | grep defunct 命令&#xff08;或ps …

嵌入式C语言高级教程:实现基于STM32的无人机飞控系统

无人机飞控系统是无人机的大脑&#xff0c;负责处理来自各种传感器的数据并控制无人机的飞行。本教程将指导如何在STM32微控制器上实现一个基础的无人机飞控系统。 一、开发环境准备 硬件要求 微控制器&#xff1a;STM32F405RGT6&#xff0c;因其高性能和大量的输入输出接口…

(动画详解)LeetCode20.有效的括号

题目描述 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 解题思路 栈的方法 遍历整个字符串 当检测到左括号的时候&#xff0c;就让左括号入栈 当检测到右括号的时候&#xff0c;就让左括号出栈与右括号对比 如果相等则继续比较直到结束&#xff0c;如果不相等…

农业生产中,土壤墒情的监测方法有哪些?

农业是人类的生命之源&#xff0c;而土壤墒情则是农业生产的基础。我们应该倍加珍惜土地资源&#xff0c;合理利用水资源&#xff0c;努力创造出更加宜人的生长环境。让每一滴水都能为农作物带来生机&#xff0c;让每一寸土地都能孕育丰收。这样才能实现农业可持续发展的目标&a…

leetCode刷题记录4-面试经典150题-2

文章目录 不要摆&#xff0c;没事干就刷题&#xff0c;只有好处&#xff0c;没有坏处&#xff0c;实在不行&#xff0c;看看竞赛题面试经典 150 题 - 2210. 课程表 II909. 蛇梯棋 不要摆&#xff0c;没事干就刷题&#xff0c;只有好处&#xff0c;没有坏处&#xff0c;实在不行…

问题:幂等性 分布式session

web项目中请求线程到service层的时候远程调用服务之前是串行化执行每个任务都要get阻塞等待任务完成&#xff0c;举例当用户在购物车页面点击去结算就会请求后台toTrade请求获取订单确认的详情数据并渲染到订单详情页&#xff0c;现在在toTrade请求中使用异步任务编排Completab…

ROS2 安装与测试

文章目录 ROS2 安装与测试ROS2 安装1. 设置编码2. 添加源3. 安装 ROS24. 设置环境变量 ROS2 示例测试实例一&#xff1a;命令行实例实例二&#xff1a;小海龟仿真实例 参考链接 ROS2 安装与测试 ROS2 安装 基于 Ubuntu 22.04 LTS 操作系统。 1. 设置编码 sudo apt update &…

【Java】/*方法的使用-快速总结*/

目录 一、什么是方法 二、方法的定义 三、实参和形参的关系 四、方法重载 五、方法签名 一、什么是方法 Java中的方法可以理解为C语言中的函数&#xff0c;只是换了个名称而已。 二、方法的定义 1. 语法格式&#xff1a; public static 返回类型 方法名 (形参列表) { //方…

JavaScript创建日期

创建日期 在JavaScript中创建日期有四种方法 ● 使用new Date() const now new Date(); console.log(now);● 直接输入月、日、年、时间 console.log(new Date(Aug 02 2024 18:05:41));● 也可以输入年月日 console.log(new Date(December 24, 2015));● 直接按照年、月、…

力扣/leetcode383.比特位记数

题目描述 给你一个整数 n &#xff0c;对于 0 < i < n 中的每个 i &#xff0c;计算其二进制表示中 1 的个数 &#xff0c;返回一个长度为 n 1 的数组 ans 作为答案。 示例 代码思路 第一种方法 最简单的方法就是&#xff0c;遍历然后使用python自带的bin()方法直接…

八年三顾A股“茅庐”无果,富友支付“减利”后只能赴港上市?

都说事不过三&#xff0c;此前三次想要“进宫”&#xff0c;却三次与A股“无缘”的富友支付&#xff0c;最终无奈选择南下港交所上市了。 据港交所披露&#xff0c;上海富友支付服务股份有限公司&#xff08;简称“富友支付”&#xff09;于2024年4月30日正式向港交所递交招股…