C++中的面向对象重点总结

面向对象的三大特性

封装

封装是将数据和操作这些数据的函数(方法)组合在一个类中的过程。

封装的主要目的是隐藏类的内部实现细节,仅暴露必要的接口给外部,通过控制类成员的访问级别,可以限制对类内部数据的直接访问,确保数据的完整性和安全性。

继承

继承是一个类(派生类)从另一个类(基类)哪里获得其属性和方法的过程。

C++中    public继承表示派生类 is-a (是一个)基类。

pricate继承表示派生类 包含(has a)基类。

多态*

定义:同一事物表现出不同事物的能力,即向不同对象发送同一消息,不同的对象在接受时会产生不同的行为(重载实现编译时多态,虚函数实现运行时多态)

功能:多态允许不同类的对象使用相同的接口名字,但具有不同实现的特性,允许将子类类型的指针赋值给父类类型的指针,

实现多态有两种方法:

1. 覆盖(override):是指子类重新定义父类的虚函数的做法

2. 重载(overload):是指允许存在多个同名函数,而这些函数的参数表不同,或许参数个数不同,或许参数类型不同,或许两者都不同

重载overload

重载是指相同作用域(比如命名空间或者同一个类)内拥有相同的方法名,但具有不同的参数类型和/或参数数量的方法。 重载允许根据所提供的参数不同来调用不同的函数。它主要在以下情况下使用:

方法具有相同的名称。
方法具有不同的参数类型或参数数量。
返回类型可以相同或不同。

同一作用域,比如都是一个类的成员函数,或者都是全局函数。

重写overriding

重写是指在派生类中重新定义基类中的方法。

当派生类需要改变或扩展基类方法的功能时,就需要用到重写。

重写的条件包括:

方法具有相同的名称。
方法具有相同的参数类型和数量。
方法具有相同的返回类型。

重写的基类中被重写的函数必须有virtual修饰。
重写主要在继承关系的类之间发生。

隐藏Hiding

隐藏是指派生类的函数屏蔽了与其同名的基类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。

类对象的初始化和析构顺序

初始化顺序

在C++中,类对象的初始化顺序遵循以下规则:

1. 基类初始化顺序:如果当前类继承自一个或多个基类,它们将按照声明顺序进学校初始化,但是在有虚继承和一般继承存在的情况下,优先虚继承。

2. 成员变量初始化顺序:类的成员变量按照它们在类定义中的声明顺序进行初始化

3. 执行构造函数

类的析构顺序

类的析构顺序和构造顺序完全相反

多态的实现方式:虚函数、纯虚函数和模板函数

虚函数、纯虚函数实现多态

虚函数是指在基类中声明的函数,它在派生类中可以被重写。

当我们使用基类指针或引用指向派生类对象时,通过虚函数的机制,可以调用到派生类中重写的函数,从而实现多态。

因此C++的多态必须满足两个条件:

1. 必须通过基类的指针或者引用调用虚函数

2. 被调用的函数是虚函数,且必须完成对基类虚函数的重写

虚函数表

虚函数是通过一张虚函数表来实现的,在这个表中,存放的是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,确定其调用的函数。

当一个类中的成员函数有虚函数时,这个类的实例内存中都有一个虚函数表的指针(vptr),虚函数表指针指向一个数组,该数组的元素就是各个虚函数的地址,通过函数的索引,我们就能直接访问对应的虚函数。

对于派生类,其虚函数表通常是在基类的虚函数表的基础上扩展而来的,当我们在子类中重写一个父类的虚函数时,在子类的虚函数表中用子类重写的函数地址去取代父类的函数地址。当调用一个虚函数时,编译器会通过对象的虚函数指针查找到该对象所属的类的虚函数表,并根据函数的索引值来找到对应的虚函数地址,然后将控制转移到该地址,实际执行该函数的代码。

所以,当我们用父类的指针来操作有一个子类的时候,程序会根据子类的续函数表调用所指的函数。

静态绑定:当我们使用派生类的指针去访问虚函数时,实际上并未发生多态,因为编译时就能够确定对象类型为派生类型,然后直接生成调用派生类虚函数的代码即可。

动态绑定:通过基类的指针或引用调用虚函数才能构成多态,因为这种情况下运行时才能确定对象的实际类型。

纯续函数

纯虚函数是一种在基类中声明但没有实现的虚函数。它的作用是定义了一种接口,这个接口需要由派生类来实现

包含纯虚函数的类被称为抽象类:抽象类仅仅提供了一些接口,但是没有实现具体的功能,作用就是制定各种接口,通过派生类来实现不同的功能,从而实现代码的复用和可扩展性。

为什么基类析构函数需要是虚函数

析构函数是进行类的清理工作,比如释放内容、关闭文件等。

为了实现多态,C++可以通过基类的指针或引用访问派生类的成员

那么,如果一个基类的析构函数不是虚函数时,则该类的虚函数表中就不会有这个析构函数的地址,当我们通过基类的指针来访问派生类且结束时,派生类的析构函数不会被调用,只会调用基类的析构函数,因为这里并没有使用到多态(析构函数不在虚函数表中),这可能会导致资源泄露。

例如:

Class Base1{public:~Base(){ cout << "Base1 destructor" <<endl;}
}Class derived1 : public Base1{public:~Derived(){ cout << "Derived1 destructor" << endl;}
}Class Base2{public:virtual ~Base(){ cout << "Base2 destructor" <<endl;}
}Class derived2 : public Base2{public:~Derived(){ cout << "Derived2 destructor" << endl;}
}int main()
{Base1 *ptr1 = new Derived1();delete ptr1;Base1 *ptr2 = new Derived2();delete ptr2;return 0;
}

该程序的运行结果为:

Base1 destructor
Derived2 destructor
Base2 destructor

模板函数多态

模板函数可以根据传递参数的不同类型,自动生成相应类型的函数代码,模板函数可以用来实现多态,例如

template <class T>
T max(T a, T b){return (a>b? a:b)}int main()
{int i=1, j = 2;char a = 's', b = 'w';cout << max(i,j) << max(a,b) << endl;return 0;
}

 

为什么C++的成员模板函数不能是virtual

因为C++的编译与链接模型是分离的

1. 从Unix/C开始,一个C/C++程序就可以被分开编译,然后用一个linker链接起来。这种模型有一个问题,就是各个编译单元可能对另一个编译单元一无所知。

2. 一个function template 最后到底会被instantiate为多少个函数,要等整个程序(所有编译单元)全部被编译完成才知。

3. virtual function的实现利用了虚函数表,这种实现中,一个类的内存布局需要在这个类编译完成的时候就被完全确定。

所以当一个虚函数是模板函数时,编译器在编译时无法为其生成一个确定的虚函数表条目,因为模板函数可以有无数个实例。但是编译时无法确定需要调用那个特定的模板实例。因此,C++规定成员函数不能既是模板函数又是虚函数。

参考:为什么C++的成员模板函数不能是 virtual 的 | 编程指北 (csguide.cn)

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

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

相关文章

【面试】Redis基础知识

题目 为什么Redis是单线程却性能很高&#xff1f; Redis是一个高性能的基于内存的键值存储系统。它之所以能够达到高性能&#xff0c;主要有以下几个原因&#xff1a; 基于内存&#xff1a;Redis将数据存储在内存中&#xff0c;而不是硬盘上&#xff0c;这使得数据的读写速度…

回首2023,期待2024!

2023&#xff0c;在改变中到来 2023年1月1日&#xff0c;我从成都冷清的学校回到了哈尔滨的老家&#xff0c;开始了保研之前的最后一个寒假 当时的目标是将之前的科研理论转化为实际&#xff0c;生产出一篇sci&#xff0c;助力保研加分 星移斗转&#xff0c;事与愿违&#x…

编译ZLMediaKit(win10+msvc2019_x64)

前言 因工作需要&#xff0c;需要ZLMediaKit&#xff0c;为方便抓包分析&#xff0c;最好在windows系统上测试&#xff0c;但使用自己编译的第三方库一直出问题&#xff0c;无法编译通过。本文档记录下win10上的编译过程&#xff0c;供有需要的小伙伴使用 一、需要安装的软件…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)子线程 WorkerThread的实现 和 线程池ThreadPool的初始化

一、子线程 WorkerThread的实现 &#xff08;1&#xff09;工作线程 线程ID&#xff1a;每个线程都有一个唯一的ID,用于标识线程的名字&#xff1a;非必需&#xff0c;主要用于识别线程互斥锁&#xff1a;线程同步条件变量&#xff1a;线程阻塞EventLoop&#xff1a;在每个子…

实战环境搭建-linux下安装jdk1.8

查看安装jdk版本信息,主要是怕之前有遗漏的,或者安装失败的java rpm -qa | grep java 显示如下信息: 卸载: rpm -e --nodeps java-1.7.0-openjdk-1.7.0.261-2.6.22.2.el7_8.x86_64 rpm -e --nodeps java-1.8.0-openjdk-1.8.0.262.b10-1.el7.x86_64 还有一些其他的命令…

工智能基础知识总结--什么是TextCNN

什么是TextCNN Yoon Kim在论文(2014 EMNLP) Convolutional Neural Networks for Sentence Classification提出TextCNN&#xff0c;该模型将卷积神经网络CNN应用到文本分类任务&#xff0c;是卷积神经网络应用到文本分析的开创性工作之⼀。 TextCNN的结构 TextCNN的结构图如下&…

【动态规划】【滑动窗口】C++算法:100154 执行操作后的最大分割数量

作者推荐 【动态规划】【字符串】扰乱字符串 本文涉及的基础知识点 C算法&#xff1a;滑动窗口总结 动态规划 LeetCode100154 执行操作后的最大分割数量 给你一个下标从 0 开始的字符串 s 和一个整数 k。 你需要执行以下分割操作&#xff0c;直到字符串 s 变为 空&#xf…

分布式事务完美解决方案:消息中间件(kafka)+ 本地事物 + 消息校对

前言 分布式事务是要保证多个服务下的多个数据库操作的一致性。分布式事务常见解决方案有&#xff1a;二阶段、三阶段和TCC实现强一致性事务&#xff0c;其实还有一种广为人知的方案就是利用消息队列来实现分布式事务&#xff0c;保证数据的最终一致性&#xff0c;也就是我们常…

JVM是如何基于虚拟机栈运行的

众所周知&#xff1a;JVM执行Java代码是靠执行引擎实现的。执行引擎有两套解释器&#xff1a;字节码解释器、模板解释器。字节码解释器比较简单&#xff0c;不多说&#xff0c;看图。本篇文章咱们讨论模板解释器执行Java代码的底层原理。 早些年研究模板解释器看到R大用汇编写的…

【Redis】非关系型数据库之Redis的介绍及安装配置

目录 前言 一、关系型数据库与非关系型数据库 1.1关系型数据库 1.2非关系型数据库 1.3两者的区别 1.4非关系型数据库产生的背景 1.5总结 二、Redis介绍 2.1Redis是什么 2.2Redis的优点 2.3Redis的使用场景 2.4那些数据适合放在缓存中 2.5Redis为什么那么快&#xf…

03-搜索与图论python

1-DFS 排列数字 N10 path[0]*N state[False]*N def dfs(u):if un:for i in range(n):print(path[i],end )print()for i in range(n):if state[i]False:path[u]i1 state[i]Truedfs(u1)#恢复现场path[u]0state[i]False nint(input()) dfs(0)采用位运算太优雅了&#xff0c;细细…

java基础-给个一键三联呗^_^哈哈

文章目录 1.注释修改注释字体三种注释方式 2.标识符和关键字3.数据类型4.类型转换5. 变量、常量、作用域6.基本运算符7.自增自减运算符、初识Math类8.逻辑运算符、位运算符9.三元运算符及小结10.包机制11.JavaDoc生成文档 1.注释 修改注释字体 打开设置Settings 三种注释方…

[Vulnhub靶机] DriftingBlues: 4

[Vulnhub靶机] DriftingBlues: 4靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/driftingblues/driftingblues4_vh.ova 靶机地址&#xff1a;192.168.67.23 攻击机地址&#xff1a;192.168.67.3 一、信息收集 …

【教学类-45-01】X-Y之间的三连加题(a+b+c=)

作品展示&#xff1a; 背景需求&#xff1a; 我常去的大4班孩子们基本都适应了0-5之间的加法题&#xff0c;做题速度极快。 为了增加“花样”&#xff0c;吸引幼儿参与&#xff0c;修改参数&#xff0c;从二连加12变为三连加111。 素材准备: 代码重点 代码展示 X-Y 之间的3…

增长中台建设与第三方平台调研

增长中台建设与第三方平台调研 前言一、增长策略 1.1 增长算法1.2 增长算法主要内容汇总1.3 增长策略参考材料二、增长中台建设 2.1 增长中台2.2 建设参考材料三、第三方增长中台 3.1 创量3.2 引力引擎3.3 增长参谋 adSpark3.4 买量小飞机&#xff08;舜飞科技&#xff09;3.5 …

Android studio ViewPager2 底部圆点指示器应用设计

一、activity_main.xml布局文件: <androidx.viewpager2.widget.ViewPager2android:id="@+id/viewpager2"android:layout_width="403dp"android:layout_height="442dp"app:layout_constraintEnd_toEndOf="parent"app:layout_const…

python编程从入门到实践(2)操作列表

3.4 列表-list-切片操作 numlist[1,2,3,4,5,6,7,8,9] numlist[::-1] #######运行结果######[9, 8, 7, 6, 5, 4, 3, 2, 1]numlist[1,2,3,4,5,6,7,8,9] numlist[::2]#######运行结果######[1, 3, 5, 7, 9]7.列表–list-常用操作符 list1[123,456] list2[456,789] list1>list2…

如何使用 CMakeLists.txt 在 CMake 项目中生成一个可执行程序

文章目录 main.cppCMakeLists.txt创建一个构建目录运行 CMake编译项目总结 main.cpp #include <iostream> /*** 代码作者&#xff1a;小秋SLAM入门实战* 开发环境&#xff1a;Ubuntu 16.04* 运行依赖&#xff1a;C 11*/ int main(int argc, char** argv){std::cout<&…

MySQL视图索引执行计划相关十五道面试题分享

目录 一. 视图 1.1 含义 1.2 操作 创建视图 修改视图 删除视图 查看视图 二. 索引 2.1 什么是索引 2.2 为什么要使用索引 2.3 优点 2.4 缺点 2.5 何时不适用索引 2.6 索引何时失效 三. 执行计划 3.1 什么是执行计划 3.2 执行计划的作用 四. 面试题 表结构 …

HTML5+CSS3小实例:人物介绍卡片2.0

实例:人物介绍卡片2.0 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><…