【C++学习手札】多态:掌握面向对象编程的动态绑定与继承机制(初识)

 

                                               🎬慕斯主页修仙—别有洞天

                                              ♈️今日夜电波:世界上的另一个我

                                                                1:02━━━━━━️💟──────── 3:58
                                                                    🔄   ◀️   ⏸   ▶️    ☰  

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


目录

首先了解形成多态的条件

接着了解多态的“三同”规则

思考

C++11 override 和 final

抽象类


首先了解形成多态的条件

        在C++中,形成多态主要依赖于以下几个条件:

  1. 继承:多态通常发生在类与类的继承关系中。一个基类(或称为父类)可以有一个或多个派生类(或称为子类),派生类继承并可能扩展基类的行为。
  2. 虚函数:在基类中声明虚函数是实现运行时多态的关键。通过在基类中使用virtual关键字声明成员函数,可以在派生类中重写这些函数,提供不同的实现。
  3. 动态绑定(迟绑定):当通过基类指针或引用调用虚函数时,具体调用哪个版本的函数(基类还是派生类的)是在程序运行时决定的,这称为动态绑定或迟绑定。这是多态行为的核心机制。
  4. 基类指针或引用:要实现多态,通常需要使用指向基类的指针或引用来操作派生类对象。这样,可以通过相同的接口来处理不同类型的派生类对象。
  5. 派生类重写虚函数:派生类必须重写基类中的虚函数以提供自己的实现。如果派生类没有重写虚函数,它将直接继承基类中的版本。
  6. 访问权限:确保派生类有足够的访问权限来重写基类中的虚函数。例如,如果基类的虚函数是私有的,则除了友元类之外,派生类将无法重写它。
  7. 析构函数的多态性:为了使通过基类指针删除派生类对象时能够正确调用派生类的析构函数,基类的析构函数应该被声明为虚函数。
  8. 纯虚函数和抽象基类:如果基类包含纯虚函数(使用= 0声明的虚函数),那么这个基类就是一个抽象基类,不能被实例化。派生类必须提供所有纯虚函数的实现,才能成为可实例化的具体类。
  9. 类型安全:C++中的RTTI(运行时类型信息)机制,如typeiddynamic_cast,允许在运行时检查和转换对象的类型,增加了多态的安全性。
  10. 编译器和内存管理:C++编译器在后台维护虚函数表(vtable)和管理动态内存分配,以确保多态行为的正确实现。

        简简单单的先看个例子吧:

#include<iostream>
using namespace std;class Person
{
public:virtual void publish(){cout << "i am a Person" << endl;}virtual ~Person() { cout << "~Person()" << endl; }
};class Student:public Person
{
public:virtual void publish(){cout << "i am a Student" << endl;}virtual ~Student() { cout << "~Student()" << endl; }
};void fun(Person& a)
{a.publish();
}void fun2(Person* A)
{A->publish();
}int main()
{Person* cc = new Person;Student* ccc = new Student;fun2(cc);fun2(ccc);delete ccc;delete cc;cout << "_________________" << endl;Person aa;Student aaa;fun(aa);fun(aaa);return 0;
}

接着了解多态的“三同”规则

        在C++中,多态性(Polymorphism)主要指的是运行时多态,它允许不同类的对象通过相同的接口调用适当的方法。这种特性通常归纳为“三同”原则:

  1. 同函数名(Same Function Name):基类和派生类中的虚函数必须具有相同的函数名。这样,当通过基类的指针或引用调用该函数时,可以根据对象的实际类型来调用正确的函数实现。
  2. 同参数列表(Same Parameter List):基类和派生类中的虚函数应该具有相同的参数列表。这意味着函数的参数数量和类型应该相同,以确保在调用时传递的参数是一致的。
  3. 同返回类型(Same Return Type):基类和派生类中的虚函数应具有相同的返回类型,或者派生类中的返回类型应该是基类中返回类型的子类型(C++11起支持协变返回类型)。这是为了确保在使用基类指针或引用调用虚函数时,返回值的类型是一致的,从而可以进行正确的赋值或操作。

        需要注意的是,从C++11开始,引入了返回类型协变的概念,即派生类重写的虚函数可以返回基类中虚函数返回类型的子类型。例如:

class Base {
public:virtual Base* clone() const {// ...}
};class Derived : public Base {
public:virtual Derived* clone() const override {// ...}
};

        在这个例子中,Derived::clone 函数的返回类型是 Derived*,它是 Base::clone 函数返回类型 Base* 的子类型,满足协变的要求。

思考

        请你思考一下以下代码的执行结果:

class A
{
public:virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }virtual void test() { func(); }
};class B : public A
{
public:void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};
int main(int argc, char* argv[])
{B* p = new B;p->test();return 0;
}

        如下给出几个选项:

A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确

        答案为:B

        分析如下:

        首先使用B类型的指针p指向了新申请的一块B类型的空间,然后调用由父类A继承下来的test()函数,此时需要注意的是:由于是父类继承下来的test()函数,那么这个函数的原型是不会改变的,那其中的this指针也是不会改变的(意思就是类型为A* 的this指针)。接下来就是多态的概念的了,是一个多态调用,派生类是可以不加virtual的,因为他会继承父类的函数声明,而子类会重写父类的实现,这里调用的是B的func()需要注意的是:父类与子类func()中的参数列表是遵循“三同原则”的。因此我们使用的是A的func的声明,也就是:virtual void func(int val = 1),但是使用的是子类的实现:{ std::cout << "B->" << val << std::endl; }。这里又有一点注意事项只有构成多态子类才会继承父类的接口,如果不构成那么就是正常调用!

C++11 override 和 final

        从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。

  1. final:修饰虚函数,表示该虚函数不能再被重写。修饰类,表示该类不能被继承
//原型
class Car
{
public:virtual void Drive() {}
};
class Benz :public Car
{
public:virtual void Drive() { cout << "Benz-舒适" << endl; }
};
//修饰类
class Car final
{
public:virtual void Drive()  {}
};
class Benz :public Car
{
public:virtual void Drive() { cout << "Benz-舒适" << endl; }
};
//修饰虚函数
class Car 
{
public:virtual void Drive() final {}
};
class Benz :public Car
{
public:virtual void Drive() { cout << "Benz-舒适" << endl; }
};

        2.override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

class Car{
public:
virtual void Drive(){}
};
class Benz :public Car {
public:
virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

抽象类

        抽象类是一种特殊的类,它不能被实例化,只能作为其他类的基类使用。

        在C++中,抽象类是一种特殊的类,它包含了至少一个纯虚函数(pure virtual function)。纯虚函数是一种没有实现的虚函数,它的声明以“= 0”结尾,表示该函数没有具体的实现,需要在派生类中被重写。

        抽象类的主要用途是为其他类提供一个公共的接口或基本的功能实现,同时强制要求派生类提供某些特定功能的实现。这样做的目的是为了保证派生类遵循某种规范或者具有某些特定的行为。由于抽象类不能被实例化,因此通常用来作为基类,通过继承机制来指导派生类的行为和属性。

        除了纯虚函数,抽象类也可以包含普通的成员函数和数据成员。这些普通成员可以在抽象类中实现,也可以留空让派生类去实现。如果一个类继承了抽象类但没有实现所有的纯虚函数,那么这个类也必须被声明为抽象类。

#include<iostream>
using namespace std;class car
{
public:virtual void drive() = 0{}
};class BMW : public car
{
public:virtual void drive(){cout << "i have a BMW" << endl;}
};class Benz : public car
{
public:virtual void drive(){cout << "i have a Benz" << endl;}
};void fun(car& aa)
{aa.drive();
}int main()
{BMW a;Benz b;fun(a);fun(b);return 0;
}

 


                     感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                        给个三连再走嘛~  

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

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

相关文章

上门回收小程序开发,互联网下发展机遇

在当下生活水平大幅度上升发展下&#xff0c;回收成为了人们日常生活中的一部分。 如今&#xff0c;随着互联网的快速发展&#xff0c;回收行业也进行了升级换代&#xff0c;由传统的线下回收门店到回收箱在到当下的线上互联网回收模式&#xff0c;迈向了“互联网废品回收”的…

Android下SF合成流程重学习之GPU合成

Android下SF合成流程重学习之GPU合成 引言 SurfaceFlinger中的图层选择GPU合成(CLIENT合成方式)时&#xff0c;会把待合成的图层Layers通过renderengine(SkiaGLRenderEngine)绘制到一块GraphicBuffer中&#xff0c;然后把这块GraphicBuffer图形缓存通过调用setClientTarget传递…

Portainer安装/快速上手

前置&#xff1a; 管理docker容器的工具 Portainer: Container Management Software for Kubernetes and Docker https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux 官网安装教程 Install Portainer CE with Docker on Linux - Portainer Documentat…

如何将阿里云服务器迁移

&#x1f4d1;前言 本文主要是如何将阿里云服务器迁移实现数据转移的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️** &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…

设计模式七大原则

七大原则有&#xff1a; 单一原则原则接口隔离原则依赖倒转原则里氏替换原则开闭原则迪米特法则合成复用原则 1 单一职责原则 1.1 基本介绍 ​ 对类来说的&#xff0c;即一个类应该只负责一项职责。 如类A负责两个不同的职责&#xff1a;职责1&#xff0c;职责2。当职责1需…

机器人路径平滑——贝塞尔曲线

文章目录 概要线性插值二次Bzier曲线三次Bzier曲线C++实现效果概要 贝塞尔曲线 (/bɛz.i.eɪ/ BEH-zee-ay) 是一种用于计算机图形学和相关领域的参数化曲线。一组离散的控制点通过公式定义平滑、连续的曲线。 本文首先叙述一阶/二阶/三阶贝塞尔曲线的基本理论,然后针对路径不…

SPSSAU【文本分析】|社会关系网络图

社会网络关系图 社会网络关系图展示关键词之间的关系情况&#xff0c;此处的关系是指‘共词矩阵’&#xff0c;即两个关键词同时出现的频数情况&#xff0c;将‘共词矩阵’信息使用可视化方式进行呈现出来&#xff0c;接下来将分别阐述‘共词矩阵’和‘社会网络关系图’。 共词…

uniapp返回上一级页面,传参,上一级通过参数重新请求数据

小程序navigateback传值_微信小程序 wx.navigateBack() 返回页面如何传递参数 - 文章...-CSDN博客 当前页面 上一级页面

模型训练 —— AI算法初识

一、背景 AI算法中模型训练的主要目的是为了让机器学习算法从给定的标注数据中学习规律、特征和模式&#xff0c;并通过调整模型内部参数&#xff0c;使模型能够对未见过的数据进行准确预测或决策。具体来说&#xff1a; 1. **拟合数据**&#xff1a;模型通过训练来识别输入数…

LCR 127. 跳跃训练【简单】

LCR 127. 跳跃训练 题目描述&#xff1a; 今天的有氧运动训练内容是在一个长条形的平台上跳跃。平台有 num 个小格子&#xff0c;每次可以选择跳 一个格子 或者 两个格子。请返回在训练过程中&#xff0c;学员们共有多少种不同的跳跃方式。 结果可能过大&#xff0c;因此结果…

羊大师:羊奶的不同口味带来了什么不同效果

羊大师&#xff1a;羊奶的不同口味带来了什么不同效果 羊奶的口味不同主要是因为其成分和加工方式的差异。尽管口味的变化可能会影响人们对羊奶的喜好程度&#xff0c;但总体而言&#xff0c;不同口味的羊奶在营养价值上并没有明显的差别。 然而&#xff0c;有些品牌的羊奶会添…

使用 apt 源安装 ROCm 6.0.x 在Ubuntu 22.04.01

从源码编译 rocSolver 本人只操作过单个rocm版本的情景&#xff0c;20240218 ubuntu 22.04.01 1&#xff0c;卸载原先的rocm https://docs.amd.com/en/docs-5.1.3/deploy/linux/os-native/uninstall.html # Uninstall single-version ROCm packages sudo apt autoremove ro…

跨境电商服务器怎么选?

随着全球化的加速和互联网的普及&#xff0c;跨境电商逐渐成为企业拓展业务的重要途径。而在跨境电商运营中&#xff0c;服务器的选择对于网站的稳定性和用户体验至关重要。本文将详细介绍如何选择适合跨境电商的服务器。 一、确定服务器需求 在选择跨境电商服务器之前&#…

【hcie-cloud】【28】华为云Stack安全管理服务

文章目录 前言信息安全管理需求安全管理的重要性典型安全事件分析等级保护管理要求等级保护中的安全管理建设安全管理中心云安全运营和管理面临的资源挑战云平台业务安全运营控制和审计问题安全运维内需云平台安全管理需求 安全管理服务详解安全运营中心SOC华为云Stack SOC服务…

shell脚本之高级变量

目录 一、高级变量赋值 1、高级变量赋值总结表 2、相关操作 二、变量间接引用 1、eval命令 一、高级变量赋值 1、高级变量赋值总结表 变量配置方式str 无配置str 为空字符串str 已配置为非空字符串var${str-expr}varexprvarvar$strvar${str:-expr}varexprvarexprvar$str…

【简洁的代码永远不会掩盖设计者的意图】如何写出规范整洁的代码

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

【EI会议征稿通知】第五届信息科学与并行、分布式处理国际学术会议(ISPDS 2024)

第五届信息科学与并行、分布式处理国际学术会议&#xff08;ISPDS 2024&#xff09; 2024 5th International Conference on Information Science, Parallel and Distributed Systems 第五届信息科学与并行、分布式处理国际学术会议&#xff08;ISPDS 2024&#xff09;定于20…

百度智能云分布式数据库 GaiaDB-X 与龙芯平台完成兼容认证

近日&#xff0c;百度智能云的分布式关系型数据库软件 V3.0 与龙芯中科技术股份有限公司的龙芯 3C5000L/3C5000 处理器平台完成兼容性测试&#xff0c;功能与稳定性良好&#xff0c;获得了龙架构兼容互认证证书。 龙芯系列处理器 通用 CPU 处理器是信息产业的基础部件&#xf…

【算法】基础算法002之滑动窗口(一)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.长度最小的子数组…

从MobileNetv1到MobileNetv3模型详解

简言 MobileNet系列包括V1、V2和V3&#xff0c;专注于轻量级神经网络。MobileNetV1采用深度可分离卷积&#xff0c;MobileNetV2引入倒残差模块&#xff0c;提高准确性。MobileNetV3引入更多设计元素&#xff0c;如可变形卷积和Squeeze-and-Excitation模块&#xff0c;平衡计算…