9、类和对象

9.1 封装

9.1.1 封装的例子

class Student {
public:string name;int age;
public:void setName(string name_) {name = name_;}
};
int main() {Student s1;s1.setName("zhangsan");return 0;
}

类中的行为都叫做成员,例如成员属性,成员变量,成员方法

9.1.2 访问权限

名称权限范围
public类内、类外都可以访问
protected类内可以访问,类外不可以访问,子类可以访问
private类内可以访问,类外不可以访问,子类不可以访问

strcut 和class 区别

  • 默认权限不同,struct 默认权限为public,class默认权限为private

9.2 对象的初始化和清理

9.2.1 构造函数与析构函数

构造函数语法: 类名(){}

  • 没有返回值也不需要用void修饰
  • 函数名与类名相同
  • 可以有参数,可以重载

析构函数语法: ~类名(){}

  • 没有返回值也不需要用void修饰
  • 函数名与类名相同
  • 可以有参数,不可以重载
  • 在对象销毁前会自动调用析构函数

9.2.2 构造函数的分类及调用

分类:

  • 按照参数:有参构造函数和无参构造函数
  • 按照类型:拷贝构造函数和普通构造函数
// 拷贝构造函数
Person(const Person &p){age=p.age;name=p.name;
}

调用:

  • 括号法:
    • 无参构造函数调用:Person p1;
    • 有参构造函数调用:Person p2(10);
    • 拷贝构造函数调用:Persiong p2(p1);
  • 显示法:
    • Person p1;
    • Person p2 = Person(10);
    • Person p3 = Person(p2);
  • 隐式法
    • Person p1=10;// 相当远Person p1=Person(10);
    • Persion p5=p4;

c++ 默认提供无参构造函数,无参析构函数以及拷贝函数

9.2.3 初始化列表

class Student {
public:string name;int age;Person():name("zhangsan"),age(10){}Person(string a,int b):name(a),age(b){}
public:void setName(string name_) {name = name_;}
};

9.2.4 类对象作为类成员

  • 当类对象作为类成员的时候,类成员的构造方法先执行,即内对象先构造,在构造外对象
  • 析构方法与构造方法相反

9.2.5 静态成员

使用static修饰的成员变量和成员函数称之为静态成员变量、静态成员函数

  • 静态成员变量:

    • 所有对象共享同一份数据
    • 在编译阶段分配内存
    • 类内声明,类外初始化
  • 静态成员函数:

    • 所有对象共享同一个函数
    • 静态成员函数只能访问静态成员变量

静态成员变量

  1. 初始化
class Student {public:string name;int age;static string school;
public:void setName(string name_) {name = name_;}
};
int deliverValue(Student s);
int deliverPlace(Student* s);
string Student::school = "黑龙江";// 静态成员变量初始化
int main() {Student s1;s1.setName("zhangsan");s1.school = "哈尔滨";// 或者直接通过某个对象初始化也可以return 0;
}
  1. 访问方式
  • 通过对象访问 s1.school
  • 通过类名访问 Student::school

静态成员函数

  1. 访问方式
  • 通过对象访问 s1.func();
  • 通过类名访问 Student::func();

9.3 C++对象模型和this指针

9.3.1 this指针

成员变量和成员函数式分开存储的,静态成员变量,静态成员函数,以及成员函数都是共享的,只有非静态成员变量是对属于对象的。
那么对于非静态成员函数是怎么区分是哪个对象调用自己的?C++通过提供特殊的对象指针this指针解决上述问题。this指针指向被调用的成员函数所属的对象。

  • this 指针隐含在每个非静态成员函数内部,不需要定义,直接可以使用

this指针的作用

  • 当形参与成员变量同名时,可以用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可以使用 return *this
class Student {public:string name;int age;static string school;
public:void setName(string name) {this->name = name;}
};

在VS2022中键盘输入this.age= 会自动修正为this->age=,对于VS2022 指针的"."相当于“->”的快捷键。

9.3.2 const修饰成员函数

  • 常函数
    • 成员函数添加const后我们称这个函数为常函数
    • 常函数内不可以修改成员属性
    • 成员属性声明时加关键字multable后,在常函数中依然可以修改
  • 常对象
    • 声明对象前加const称该对象为常对象
    • 常对象只能调用常函数

常函数如下:

void show(string name) const {cout<<this->name;
}

const 本质上是修饰的this指针

9.3 友元

  • 全局函数做友元
  • 类做友元
  • 成员函数做友元

9.3.1 全局函数做友元

在类中加入friend修饰的函数声明,就可以将该函数定义为当前类的友元

class Student {friend void visit(Student* s);
public:string name;int age;static string school;
private:string score;
public:void setName(string name) {this->name = name;}void show(string name) const {cout<<this->name;}
};
void visit(Student* s) {cout << s->score;
}

9.3.2 类做友元

在类中加入friend修饰的类声明,就可以将该类定义为当前类的友元

9.3.2 类做友元

在类中加入friend修饰的类声明,就可以将该类定义为当前类的友元

friend Person p;

9.3.2 成员函数做友元

在类中加入friend修饰的成员函数声明,就可以将成员函数定义为当前类的友元

	friend void GoodGay::visit();

9.4 运算符重载

9.4.1 对于加号进行重载

  • 成员函数重载
class Person(){Person operator+(Person &p){}
}
// 使用的时候
Person p3=p1.operator+(p2);
// 或者
Person p3=p1+p2;
  • 全局函数重载
Person operator+(Person &p1, Person &p2){}
// 使用的时候
operator+(p1,p2)
// 或
Person p3=p1+p2;

9.4.2 对左移运算符进行重载

在输出的时候cout<< 无法对自定义类进行输出,所以可以对<<进行重载
通常情况下不会使用成员函数重载<<。因为无法简化为cout<<p。

  • 使用全局函数重载<<
ostream& operator<<(ostream &cout,Person &p){cout<<p.name;rerturn cout;
}

9.4.3 递增运算符重载

  • 前置递增重载(成员函数重载)
MyInteger& operator++(){m_num++;return *this;
}

这里必须要返回引用,当不返回引用的时候,两次连续的递增操作会出现问题

MyInteger a(0);// a.m_num=0;
cout<<++(++a);// 输出2  cout 重载过的函数,输出的是a.m_num的值
cout<<a;//输出1 

这是因为如果不返回引用,那么会第一次++a会返回一个a的副本,即匿名对象,然后第二次递增是对于这个副本进行递增,因此递增的结果是正确的,但是真正的a.m_num只递增了一次

  • 后置递增重载
MyInteger& operator++(int){
MyInteger tmp=*this;m_num++;return tmp;
}

这里需要注意,后置递增两次连加本身就是无法加2的,因为后置递增是先返回原值,在执行加法,即普通的int a=0;(a++)++也是等于1,在vs2022会直接报错,显示“表达式必须是可修改的左值”

9.4.4 赋值运算符重载

Person& operator=(Person &p){// 要先对原本对象存在堆区里的数据进行释放,否则就会存在一直不释放的数据if(m_Age!=NUll){delete m_Age;m_Age=NULL;}m_Age= new int*p.m_Age);return *this;
}

9.4.5 关系运算符重载

Person& operator==(Person &p){if(m_Age==p.m_Age){return true;}return false;
}

9.4.6 函数调用运算符重载(仿函数)

class MyAdd{
public:void operator()(String s){cout<<s<<endl;}
}void test(){MyAdd myadd;int ret = myadd(100,100);cout<<ret<<endl;
}

9.5 继承

9.5.1 继承

class 子类:继承方式 父类
(子类也叫基类,父类也叫基类)

9.5.2 继承方式

  • public:权限不变,即父类中的私有还是私有不可访问,受保护的还是受保护的,可以访问
  • protected:父类中的公共权限和保护权限在子类中全部变为保护权限,私有不可访问
  • private:公共权限和保护权限都变为私有权限,私有不可访问

9.5.3 继承中的对象

在父类中的任何非静态属性都会在子类中存在一份,只不过是父类的私有属性,无法访问

9.5.4 继承中的构造和析构顺序

base构造
son构造
son析构
base析构

9.5.5 继承中同名成员访问

class Base{publicBase(){m_A=100;}
}class Son :public Base{publicSon(){m_A=200;}
}int main(){Son s;cout<<"son"<<s.m_A<<endl;cout<<"Base"<<s.Base::m_A<<endl;
}

成员函数的调用方法和成员属性的调用方法类似

注意:当子类和父类中出现同名成员函数时,父类中的所有同名成员函数被隐藏,即子类中出现change()函数,那么父类中的change(),change(int a)等等都会被隐藏,一定要调用的时候加父类作用域。

9.5.6 多继承

class 子类:继承方式 父类1,继承方式 父类2

在实际开发中通常不建议使用多继承,父类属性出现重名情况是每次调用都需要明确作用域

9.5.6 菱形继承

在这里插入图片描述

  • 两个父类存在相同的属性,可以通过加作用域区分 s.Sheep:m_Age; s.Tuo:m_Age;
  • 存在重复属性,造成了数据的冗余,浪费内存。利用虚继承来解决:class Sheep:virtual public Animal;class Tuo:virtual public Animal; 这种情况下,s.Sheep:m_Age; s.Tuo:m_Age;是同一份数据

9.6 多态

9.6.1 基本概念

  • 静态多态:函数重载、运算符重载以及复用函数名都属于静态重载
  • 动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态的根本区别:

  • 静态多态的函数地址早绑定,编译阶段确定函数地址
  • 动态多态的函数地址晚绑定,运行阶段确定函数地址
class Animal{
public:virtual void speack(){// 如果不使用虚函数,那么test函数执行的时候无论输入的是小猫,小狗都是“动物在说话”cout<<"动物在说话";}
}
class Catpublic Animal{
public:void speack(){cout<<"猫在说话";}
}
void test(Animal &animal){animal.speak();
}

动态多态满足条件:

  • 有继承关系
  • 子类重写父类的虚函数

重写:函数名与参数完全相同

在这里插入图片描述

9.6.2 纯虚函数和抽象类

  • 语法:virtual 返回值类型 函数名(参数列表)= 0;
  • 当类中存在纯虚函数那么这个类被称为抽象类
  • 抽象类特点:
    • 抽象类的子类必须重写纯虚函数。
    • 抽象类无法实例化对象

9.6.3 虚析构和纯虚析构

问题:多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,会造成内存溢出
解决办法:将父类中的析构函数改成虚析构或者纯虚析构

父类的纯虚析构代码要在类外实现


Animal::~Animal(){}

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

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

相关文章

飞速(FS)S5800-48T4S:如何使用MLAG?

MLAG&#xff08;多机箱链路聚合组&#xff09;可实现无缝故障转移并优化带宽利用率&#xff0c;从而增强网络冗余和提高可扩展性。它允许多台交换机作为一个统一实体运行&#xff0c;从而降低停机风险并确保网络运行不中断。飞速&#xff08;FS&#xff09;S5800-48T4S是一款支…

二维高斯函数的两种形式

第一种形式很常见 多元正态分布 多元正态分布&#xff08;Multivariate Normal Distribution&#xff09;&#xff0c;也称为多变量正态分布或多维正态分布&#xff0c;是统计学中一种重要的概率分布&#xff0c;用于描述多个随机变量的联合分布。 假设有 n n n 个随机变量…

【LabVIEW学习篇 - 18】:人机界面交互设计02

文章目录 错误处理函数简单错误处理器通用错误处理器清楚错误合并错误错误代码至错误簇转换查找第一个错误 鼠标指针 错误处理函数 在LabVIEW中&#xff0c;是通过错误输入簇和错误输出簇来传递错误信息&#xff0c;可以将底层错误信息传递到上层VI。设计人员需要对不同程度的…

2024 数学建模高教社杯 国赛(C题)| 农作物的种植策略 | 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;运用等多目标规划等强大工具&#xff0c;构建了这一题的详细解答哦&#xff01; 为大家量身打造创新解决方案。小秘籍团队&#xff0c;始终引领着建模问题求解的风潮。 抓紧小秘籍&#xff0c;我们出发…

高并发内存池(一):项目介绍与定长内存池的实现

目录​​​​​​​ 项目介绍 池化技术 内存池 内存碎片 malloc工作原理 定长内存池 申请内存 释放内存 定位new VirtualAlloc函数 封装VirtualAlloc 定长内存池的最终代码 项目介绍 项目原型&#xff1a;goole的开源项目tcmalloc&#xff08;Thread-Caching Mal…

CIOE中国光博会&电巢科技即将联办“智能消费电子创新发展论坛”

在科技浪潮汹涌澎湃的当下&#xff0c;从通信领域的高速光传输&#xff0c;到消费电子中的高清显示与先进成像技术&#xff0c;光电技术的应用范围不断拓展且日益深化。而AIGC 凭借其丰富的内容供给与个性化反馈能力&#xff0c;正为新一代消费电子及智能穿戴产品开辟崭新的发展…

前端请求的路径baseURL怎么来的 ?nodejs解决cors问题的一种方法

背景&#xff1a;后端使用node.js搭建&#xff0c;用的是express 前端请求的路径baseURL怎么来的 &#xff1f; 前后端都在同一台电脑上运行&#xff0c;后端的域名就是localhost&#xff0c;如果使用的是http协议&#xff0c;后端监听的端口号为3000&#xff0c;那么前端请求…

S3C2440开发板:时钟,PWM定时器控制蜂鸣器发声

时钟 时钟和电源管理模块由三部分组成&#xff1a;时钟控制&#xff0c;USB 控制和电源控制。 S3C2440A 中的时钟控制逻辑可以产生必须的时钟信号&#xff0c;包括 CPU 的 FCLK&#xff0c;AHB 总线外设的 HCLK 以及 APB 总线外设的 PCLK。S3C2440A 包含两个锁相环&#xff08…

VBA进行excel坐标转换

在Excel里利用坐标绘图时&#xff0c;可以比较容易想到采用数据透视表&#xff0c;但是数据透视表生成的图不可更改&#xff0c;因此本案例采用VBA进行坐标变换而不改变原始值来转换图像&#xff0c;即实现图像的左右翻转和上下翻转&#xff0c;如下图所示&#xff0c;选择map的…

fastadmin 文件上传腾讯云

1-安装腾讯云SDK composer require qcloud/cos-sdk-v5 2-腾讯云配置 <?phpnamespace app\common\controller;use Qcloud\Cos\Client; use think\Controller; use think\Db;class Tencent extends Controller {/*** 上传文件* param $config* param $key* return array*/p…

Linux下快速判断当前终端使用的是bash or csh

在Linux下设置环境变量的时候&#xff0c;可能你也遇到过export: Command not found一类的错误。这是因为当前终端使用的不是bash&#xff0c;如何快速判断当前终端使用的是哪种类型的shell呢&#xff1f; echo $0判断shell类型 最简单的方法就是在终端输入echo $0&#xff0…

每日一题,零基础入门FPGA——工程师在线精讲来咯

传送门&#xff1a;zzfpga.com/StudentPlatform/Train/StudentArticleDetails?id149

M3U8工作原理以及key解密视频流详解

文章目录 前言一、M3U8是什么&#xff1f;二、HLS—M3U8的工作原理1.分段视频流2.生成播放列表3.客户端请求和解析4.片段下载和播放 三、.m3u8文件内部是什么样的&#xff1f;四、简单介绍下AES-128算法五、拿到KEY后如何去解密&#xff1f;1.手动解密.ts文件2.前人栽树&#x…

spring security 如何解决跨域的

一、什么是 CORS CORS(Cross-Origin Resource Sharing) 是由 W3C制定的一种跨域资源共享技术标准&#xff0c;其目就是为了解决前端的跨域请求。在JavaEE 开发中&#xff0c;最常见的前端跨域请求解决方案是早期的JSONP&#xff0c;但是JSONP 只支持 GET 请求&#xff0c;这是一…

深度学习从入门到精通——基于unet++算法实现细胞分割

模型定义 import torch from torch import nn__all__ [UNet, NestedUNet]class VGGBlock(nn.Module):def __init__(self, in_channels, middle_channels, out_channels):super().__init__()self.relu nn.ReLU(inplaceTrue)self.conv1 nn.Conv2d(in_channels, middle_channe…

FPGA速度优化

速度优化 文章目录 速度优化前言一、时序优化1.1 减少关键路径上的时序1.1.1 关键路径重组1.1.2 解决扇出问题1.1.3 路径上插入寄存器1.1.4 寄存器平衡1.1.5 并行结构1.1.6 消除代码优先级 总结 前言 速度优化&#xff0c;主要就是设计时序进行优化 吞吐量&#xff1a;每个时…

web渗透:RCE漏洞

RCE漏洞&#xff0c;即远程代码执行漏洞&#xff0c;是一种安全缺陷&#xff0c;它允许攻击者通过网络在目标系统上执行任意代码。一旦成功利用&#xff0c;攻击者可以完全控制受影响的系统&#xff0c;包括读取敏感数据、安装恶意软件、修改系统配置等。RCE漏洞通常发生在应用…

数据结构---双向链表---循环链表---栈

目录 一、双向链表 1.1.创建双向链表 1.2.头插法 1.3.尾插法 1.4.查询节点 1.5.修改节点 1.6.删除节点 1.7.打印节点 1.8.销毁链表 二、循环链表 2.1.单循环链表 2.2.双循环链表 三、栈 3.1.顺序栈 1.创建栈 2.判断栈是否满 3.判断栈是否为空 4.进栈 5.出栈…

SAP 生产订单工序删除状态撤回简介

SAP 生产订单工序删除状态撤回简介 一、业务场景二、处理办法三、系统控制一、业务场景 生产订单正常没有按工序分配物料,系统会自动会把物料分配到第一道工序中 生产订单中的0010工序中对应的组件的栏位被标识,表示有物料分配到了0010的工序中,正常情况下0010的工序被分配…

【微服务】springboot 自定义注解+反射+aop实现动态修改请求参数

目录 一、前言 二、动态修改接口请求参数的场景 2.1 动态修改请求参场景汇总 2.1.1 数据格式标准化 2.1.2 安全需要 2.1.3 参数校验与默认值设定 2.1.4 数据隐私保护 2.1.5 适配不同客户端 2.1.6 统计与监控 2.1.7 高级功能特性 三、springboot 使用过滤器和拦截器动…