C++入门 ——类和对象(二)

this指针

this指针的引出

我们先来定义一个日期类 Date

class Date
{ 
public:
 void Init(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 void Print()
 {
 cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }
private:
 int _year;     // 年
 int _month;    // 月
 int _day;      // 日
};
int main()
{
 Date d1, d2;
 d1.Init(2022,1,11);
 d2.Init(2022, 1, 12);
 d1.Print();
 d2.Print();
 return 0;
}

对于上述类,有这样的一个问题:

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成。

this指针的特性

1. this指针的类型:类型* const,即成员函数中,不能给this指针赋值。

2. 只能在“成员函数”的内部使用

3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。

4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传 递,不需要用户传递

C语言和C++实现Stack的对比

C语言实现

typedef int DataType;
typedef struct Stack
{
 DataType* array;
 int capacity;
 int size;
}Stack;
void StackInit(Stack* ps)
{
 assert(ps);
 ps->array = (DataType*)malloc(sizeof(DataType) * 3);
 if (NULL == ps->array)
 {
 assert(0);
 return;
 }
 ps->capacity = 3;
 ps->size = 0;
}
void StackDestroy(Stack* ps)
{
 assert(ps);
 if (ps->array)
 {
 free(ps->array);
 ps->array = NULL;
 ps->capacity = 0;
 ps->size = 0;
 }
}
void CheckCapacity(Stack* ps)
{
 if (ps->size == ps->capacity)
 {
 int newcapacity = ps->capacity * 2;
 DataType* temp = (DataType*)realloc(ps->array, 
newcapacity*sizeof(DataType));
 if (temp == NULL)
 {
 perror("realloc申请空间失败!!!");
 return;
 }
 ps->array = temp;
 ps->capacity = newcapacity;
 }
}
void StackPush(Stack* ps, DataType data)
{
 assert(ps);
 CheckCapacity(ps);
 ps->array[ps->size] = data;
 ps->size++;
}
int StackEmpty(Stack* ps)
{
 assert(ps);
 return 0 == ps->size;
}
void StackPop(Stack* ps)
{
 if (StackEmpty(ps))
 return;
 ps->size--;
}
DataType StackTop(Stack* ps)
{
 assert(!StackEmpty(ps));
 return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{
 assert(ps);
 return ps->size;
}
int main()
{
 Stack s;
 StackInit(&s);
 StackPush(&s, 1);
 StackPush(&s, 2);
 StackPush(&s, 3);
 StackPush(&s, 4);
 printf("%d\n", StackTop(&s));
 printf("%d\n", StackSize(&s));
 StackPop(&s);
 StackPop(&s);
 printf("%d\n", StackTop(&s));
 printf("%d\n", StackSize(&s));
 StackDestroy(&s);
 return 0;
}

可以看到,在用C语言实现时,Stack相关操作函数有以下共性:

每个函数的第一个参数都是Stack*

函数中必须要对第一个参数检测,因为该参数可能会为NULL

函数中都是通过Stack*参数操作栈的

调用时必须传递Stack结构体变量的地址

结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。

C++实现

typedef int DataType;
class Stack
{
public:
 void Init()
 {
 _array = (DataType*)malloc(sizeof(DataType) * 3);
 if (NULL == _array)
 {
 perror("malloc申请空间失败!!!");
 return;
 }
 _capacity = 3;
 _size = 0;
 }
void Push(DataType data)
 {
 CheckCapacity();
 _array[_size] = data;
 _size++;
 }
 void Pop()
 {
 if (Empty())
 return;
 _size--;
 }
 DataType Top(){ return _array[_size - 1];}
 int Empty() { return 0 == _size;}
 int Size(){ return _size;}
 void Destroy()
 {
 if (_array)
 {
 free(_array);
 _array = NULL;
 _capacity = 0;
 _size = 0;
 }
 }
private:
 void CheckCapacity()
 {
 if (_size == _capacity)
 {
 int newcapacity = _capacity * 2;
 DataType* temp = (DataType*)realloc(_array, newcapacity * 
sizeof(DataType));
 if (temp == NULL)
 {
 perror("realloc申请空间失败!!!");
 return;
 }
 _array = temp;
 _capacity = newcapacity;
 }
 }
private:
 DataType* _array;
 int _capacity;
 int _size;
};
int main()
{
 Stack s;
 s.Init();
 s.Push(1);
 s.Push(2);
 s.Push(3);
 s.Push(4);
 
 printf("%d\n", s.Top());
 printf("%d\n", s.Size());
 s.Pop();
 s.Pop();
 printf("%d\n", s.Top());
 printf("%d\n", s.Size());
 s.Destroy();
 return 0;

C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在 类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。 而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原,即C++中 Stack * 参数是编译器维护的,C语言中需用用户自己维护。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue+Mysql的自习室预订系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Springboot工程创建

目录 一、步骤 二、遇到的问题及解决方案 一、步骤 打开idea,点击文件 ->新建 ->新模块 选择Spring Initializr&#xff0c;并设置相关信息。其中组为域名&#xff0c;如果没有公司&#xff0c;可以默认com.example。点击下一步 蓝色方框部分需要去掉&#xff0c;软件包…

牛客NC382 切割木头【中等 二分超找 Java/Go/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/707d98cee255448c838c76918a702be0 核心 二分查找Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可…

SpringBoot指标监控

一.SpringBoot指标监控_添加Actuator功能 Spring Boot Actuator可以帮助程序员监控和管理SpringBoot应用&#xff0c;比如健康检查、内存使用情况统计、线程使用情况统计等。我 们在SpringBoot项目中添加Actuator功能&#xff0c;即可使用Actuator监控 项目&#xff0c;用法如…

Vue的项目启动指令分析

通过Vue CLI脚手架创建的项目&#xff0c;默认的启动项目方式是 npm run serve 这里的serve是可以修改的。 在创建的项目目录中&#xff0c;找到package.json 双击打开&#xff0c;找到scripts部分 在scripts部分&#xff0c;有一个"serve"键值对&#xff0c;这里的…

知乎23届数据分析校招A卷——笔记

1、and 和 or的并列运用[先看and] 条件1 OR 条件2 AND 条件3 执行顺序是先执行AND操作符&#xff08;先看条件2和3&#xff09;&#xff0c;再根据其结果判断是否需要执行OR操作符&#xff0c;并最终返回整个表达式的逻辑结果。 条件1 and 条件2 or 条件3 执行逻辑是先执行…

使用socket+Python实现ping

import os import socket import struct import select import time# 计算校验和&#xff0c;用于确保数据的完整性 def checksum(source_string):sum 0count 0max_count len(source_string)# 处理成对的字节while count < max_count - 1:val source_string[count 1] *…

nginx的前世今生(二)

书接上回&#xff1a; 上回书说到&#xff0c;nginx的前世今生&#xff0c;这回我们继续说 3.缓冲秘籍&#xff0c;洪流控水 Nginx的缓冲区是其处理数据传输和提高性能的关键设计之一&#xff0c;主要用于暂存和管理进出的数据流&#xff0c;以应对不同组件间速度不匹配的问题…

PG WAL日志理解

类似于oracle的redo log&#xff0c;用于数据库恢复&#xff0c;当一条SQL语句执行&#xff0c;PG会把对应的块放到缓冲区执行&#xff0c;&#xff0c;会写进WAL缓冲区会进行写操作&#xff0c;commit后&#xff0c;WAL writer进程进行写操作&#xff0c;把日志缓冲区WAL buff…

SpringData JPA - ORM 框架下,打造高效数据访问层

目录 一、SpringData JPA 概述 1.1、什么是 JPA 1.2、什么是 ORM 1.3、什么是 Hibernate 1.4、JPA 和 Hibernate 的关系 1.5、JPA 的优势 二、SpringData JPA 实战开发 2.1、依赖 2.2、配置文件 2.3、启动类 2.4、创建实体 2.5、基于 JpaRepository 的 CRUD 三、…

超市购物|基于SprinBoot+vue的超市购物系统(源码+数据库+文档)

目录 基于SprinBootvue的企业人事管理系统 一、前言 二、系统设计 三、系统功能设计 1商品管理 2公告管理 3公告类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设…

C语言--带环链表问题

继续学习 一、判断链表是否带环 141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;用快慢指针&#xff0c;快指针走两步&#xff0c;慢指针走一步&#xff0c;当慢指针走一半快指针进到环里 当慢指针进环&#xff0c;快指针已经在环中转了一会儿了 | |…

“字节跳动-文远知行杯”——广东工业大学第十四届程序设计竞赛

补题补题&#xff1a; A、hzy 和zsl 的生存挑战 题解&#xff1a;由于我们去考虑最优解&#xff0c;那么其中两人就应该是这样走法&#xff0c;一人选择相同数&#xff0c;另一人选择相反数&#xff0c;这样必会通关 #include <iostream> using namespace std;int main(…

Web服务器手动配置

目录 配置环境 http配置 配置步骤 1、首先安装Nginx&#xff08;已经安装的跳过这步&#xff09; 2、查看一下下Nginx的配置文件结构&#xff0c;了解如何配置&#xff0c;以及配置的各个条目有什么作用&#xff08;为接下来的配置打基础&#xff09; 3、创建你的网页 4、…

【银角大王——Django课程——靓号搜索实现/单独一篇】

搜索框功能实现 靓号搜索在Django框架中搜索功能实现——底层就是模糊查询添加一个搜索框&#xff0c;使用bootstrap框架将GO&#xff01;修改成一个放大镜靓号列表函数代码解释效果演示 靓号搜索 在Django框架中搜索功能实现——底层就是模糊查询 数字条件用法字符串条件用法…

学习如何使用PyQt5实现notebook功能

百度搜索“pyqt5中notebook控件”&#xff0c;AI自动生成相应例子的代码。在 PyQt5 中&#xff0c;QTabWidget 类被用作 Notebook 控件。以下是一个简单的示例&#xff0c;展示如何创建一个带有两个标签的 Notebook 控件&#xff0c;并在每个标签中放置一些文本。 import sys f…

电子信息工程专业就业前景怎么样

电子信息工程专业的就业前景十分广阔&#xff0c;主要得益于现代社会对信息技术的依赖不断加深以及科技的快速发展&#xff0c;以下是上大学网&#xff08;www.sdaxue.com&#xff09;对该专业就业前景的具体分析&#xff0c;供大家参考&#xff01; 行业需求广泛&#xff1a;随…

VBA字典与数组第十四讲:单列数组与单行数组间的运算

《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;字典是VBA的精华&#xff0c;我要求学员必学。7.1.3.9教程和手册掌握后&#xff0c;可以解决大多数工作中遇到的实际问题。…

动态规划 ------ 背包问题

文章目录 1. 01 背包问题1.二维解决2. 一维优化 2. 完全背包问题1.暴力3 for.2. 二维优化3. 一维优化 3. 多重背包问题Ⅰ.1. 二维解决2. 一维优化 4. 多重背包问题Ⅱ5. 混合背包问题6. 二维费用背包问题7. 分组背包问题 背包问题是动态规划中非常典型的一些题&#xff0c;本篇文…

ctfshow——SSRF

文章目录 web 351web 352web 353web 354web 355web 356web357web 358web 359web 360 SSRF(Server-Side Request Forgery&#xff1a;服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统…