9、类和对象

news2024/9/21 0:33:30

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.coloradmin.cn/o/2107673.html

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

相关文章

磁吸轨道灯的优缺点深度解析:为你的家居照明提供新选择

在现代家居装修中&#xff0c;照明设计已成为提升居住品质的重要一环。磁吸轨道灯作为一种新兴的照明解决方案&#xff0c;以其独特的灵活性和美观性逐渐受到市场的青睐。然而&#xff0c;任何产品都有其两面性&#xff0c;磁吸轨道灯也不例外。本文将深入探讨磁吸轨道灯的优缺…

产品起名|给你的产品插上会飞的翅膀

引言&#xff1a;在品牌的世界里&#xff0c;产品的名字不仅仅是一个标签&#xff0c;它是品牌个性、价值和承诺的直接体现。一个好的产品名能够快速传达产品特性&#xff0c;吸引消费者&#xff0c;并在市场中建立独特的品牌形象。 好产品从起名开始 品牌介绍&#xff1a;南京…

使用卫星仿真软件STK的一些应用和思考(星地链路、星间链路)

目录 任务描述利用STK建模星地协同系统3个GEO高轨卫星240/20/1 Walker-Star Constellation 低轨卫星星座地面站或者地面设备 链路建模与数据提取处理星地链路星间链路数据读取的几种方法最麻烦的方法使用Matlab与STK互联接口使用大规模使用Chain 总结 任务描述 在一个星地协同…

【小设计】基于宏实现的C++ 可复用setter 和getter设计

前言 最近在开发unity游戏的时候&#xff0c;面对庞大复杂的不同类之间进行数据交换和调用&#xff0c;我们必须做好类数据的信息管理&#xff0c;往往我希望暴露给其他类越少越好&#xff0c;这时候我就利用了C#的一个语言特性 public PlayerStateMachine stateMachine{get;…

创建锁对象/函数

描述&#xff1a;某些单据进行修改时&#xff0c;需要锁定数据 方法步骤&#xff1a; 1、se11&#xff1a;可copy创建新锁 EZSDDH 2、输入需要锁定的主表&#xff0c;锁参数会根据主键自动补填 3、激活后&#xff0c;会生成对应的锁函数 ENQUEUE_EZSDDH &#xff1a;锁定表 …

评论的组件封装

主评论的人在数组第一层级&#xff0c;回复的评论都在children里面 【{ name:"张三" idGenerator: 475403892531269 info_Conmment":"今天天气晴朗&#x1f600;" children:[ { mainIdGenerator:475388950118469 name:"张三" name1&#x…

Java 入门指南:Java 并发编程 —— 并发容器 BlockingDeque、LinkedBlockingDeque

BlockingQueue BlockingQueue 是Java并发包&#xff08;java.util.concurrent&#xff09;中提供的一个阻塞队列接口&#xff0c;它继承自 Queue 接口。 BlockingQueue 中的元素采用 FIFO 的原则&#xff0c;支持多线程环境并发访问&#xff0c;提供了阻塞读取和写入的操作&a…

Jenkins构建CI/CD

CI/CD 软件开发的连续方法基于自动执行脚本&#xff0c;以最大限度地减少在开发应用程序时引入错误的可能性。从新代码的开发到部署&#xff0c;它们需要较少的人为干预甚至根本不需要干预。 它涉及在每次小迭代中不断构建&#xff0c;测试和部署代码更改&#xff0c;从而减少…

多线程 | synchronized的简单使用

synchronized 关键字是 Java 中解决并发问题的一种常用方法&#xff0c;也是最简单的一种方法&#xff0c;其作用有三个: &#xff08;1&#xff09;互斥性&#xff1a;确保线程互斥的访问同步代码 &#xff08;2&#xff09;可见性&#xff1a;保证共享变量的修改能够及时可见…

UOS系统通过Remmina远程windows系统桌面

windows系统之间可以互相进行远程桌面连接&#xff0c;那么UOS系统是否可以远程到windows系统桌面呢&#xff1f;请见下面的文章。 下载安装Remmina软件 首先我们需要在UOS系统上面找到应用商店&#xff0c;下载并安装一个Remmina软件 windows系统开启允许远程桌面连接 wind…

记录ssl epoll的tcp socket服务端在客户端断开时崩溃的问题

文章目录 当客户端关闭后&#xff0c;Epoll 的 TCP socket 服务端会收到两次断开事件可能有以下原因及解决方法&#xff1a;原因分析解决方法 问题ssl socket服务端代码出错现象第一次尝试修改正确改法附上客户端代码 记录ssl epoll的tcp socket服务端在客户端断开时接收到多次…

聚铭网络入选“2024年南京市工程研究中心”认定名单

为深入实施创新驱动发展战略&#xff0c;因地制宜发展新质生产力充分发挥工程研究中心对推进产业强市的重要支撑作用&#xff0c;根据《南京市工程研究中心管理办法》&#xff0c;南京市发展和改革委员会于2024年5月组织开展了本年度南京市工程研究中心遴选工作。经企业申报、各…

编译安装调试 scaLapack 和 openmpi 以及 lapack

编译安装调试 scaLapack /home/hipper/ex_scalapack/ mkdir ./lapack mkdir -p ./lapack/local/lib mkdir ./openmpi mkdir ./scalapack 1&#xff0c;编译安装 Lapack 下载代码&#xff1a; cd lapack wget https://github.com/Reference-LAPACK/lapack/archive/refs/tags/…

[全网首发]2024国赛数学建模ABCE题完整思路+py(matlab)代码+成品论文参考+持续更新

AB题详细思路(含问题一问题二模型) CE题问题一代码思路已经写好[pythonmatlab两种都会更新 需要完整版的看这里&#xff1a; 点击链接加入群聊【2024数学建模国赛资料汇总】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&klZncBILk30DuPRI1Bd8X-3Djv7ZVZyAv&…

【非零段划分 / 2】

题目 思路 第一种思路&#xff1a;按照表面题意&#xff0c;枚举p&#xff0c;处理数组后进行计数&#xff1a; 复杂度 ∈ O ( n ⋅ m ) 复杂度 \in O(n \cdot m) 复杂度∈O(n⋅m) 第二种思路&#xff1a;把数组看成一个二维的山形图&#xff0c;先将相邻的水平线段转化成点…

Java核心知识体系-并发与多线程:线程基础

1 先导 Java线程基础主要包含如下知识点&#xff0c;相信我们再面试的过程中&#xff0c;经常会遇到类似的提问。 1、线程有哪几种状态? 线程之间如何转变&#xff1f; 2、线程有哪几种实现方式? 各优缺点&#xff1f; 3、线程的基本操作&#xff08;线程管理机制&#xff…

数据资产入表元年,企业如何抓住数据资产增值的机遇?

近年来&#xff0c;政府将数据要素纳入了经济发展的重要指示性文件当中&#xff0c;希望利用数据驱动。《全国数据资源调查报告&#xff08;2023年&#xff09;》显示&#xff0c;2024年以来不少地方纷纷成立“数据集团”&#xff0c;加快盘活数据资产。作为数字经济时代的首要…

Java | Leetcode Java题解之第389题找不同

题目&#xff1a; 题解&#xff1a; class Solution {public char findTheDifference(String s, String t) {int ret 0;for (int i 0; i < s.length(); i) {ret ^ s.charAt(i);}for (int i 0; i < t.length(); i) {ret ^ t.charAt(i);}return (char) ret;} }

编写Dockerfile第二版

目标 更快的构建速度 更小的Docker镜像大小 更少的Docker镜像层 充分利用镜像缓存 增加Dockerfile可读性 让Docker容器使用起来更简单 总结 编写.dockerignore文件 容器只运行单个应用 将多个RUN指令合并为一个 基础镜像的标签不要用latest 每个RUN指令后删除多余文…

leetcode172. 阶乘后的零,遍历每个因数中5的个数

leetcode172. 阶乘后的零 给定一个整数 n &#xff0c;返回 n! 结果中尾随零的数量。 提示 n! n * (n - 1) * (n - 2) * … * 3 * 2 * 1 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;0 解释&#xff1a;3! 6 &#xff0c;不含尾随 0 示例 2&#xff1a; 输…