C++面向对象程序设计 - 对象指针和this指针

        在C++学习中,指针是一个用于指向另一个变量的地址的变量。理解指针有一定难度,但是理解它的工作原理后,会发现它们是非常强大和有用的工具。指针可以用来指向一般的变量,也可以指向对象。

一、指向对象的指针

        在建立对象时,编译系统会为每一个对象分配一定的存储空间,以存放其成员。对象空间的起始地址就是对象的指针。

        定义指向类对象的指针变量的一般形式为:

类名 *对象指针名

        首先创建一个类,代码如下:

class Timer{
	public:
		int hour;
		int minute;
		int second;
		Timer(){
			hour = 0;
			minute = 0;
			second = 0;
		}
		Timer(int h, int m, int s): hour(h), minute(m), second(s){}
		void show_time(){
			cout <<hour <<':' <<minute <<':' <<second <<endl;
		}
};

        定义指向Timer类对象的指针变量,代码如下:

int main(){
	Timer *pt, t1;
	pt = &t1;
	return 0;
}

        通过对象指针访问对象成员,代码如下:

int main(){
	Timer *pt, t1;
	pt = &t1;
	// 直接访问hour
	cout <<"hour:" <<pt->hour <<endl;
	cout <<"hour:" <<(*pt).hour <<endl;
	// 访问成员函数
	pt->show_time();
	(*pt).show_time();
	return 0;
}

       运行结果如下:

  1. pt->hour这种方式是通过 "->"运算符直接调用指针pt所指向对象的hour成员变量。
  2. (*pt).hour这种方式是通过解引用 *pt 来获取指针pt所指向的对象,然后通过点"."运算符来调用该对象的hour成员变量。

        这两种访问指针所指向对象的成员函数的等价方式,pt是指向Timer对象的指针。大多情况下,使用pt->hour和pt->show_time()的方式更为简洁和直观。

二、指向对象成员的指针

        对象有地址,对象中的成员也有地址,存放对象成员地址的指针就是指向对象成员的指针变量。

        定义指向对象数据成员的指针变量的一般形式:

数据类型名 *指针变量名

        在类外通过指向对象数据成员的指针变量访问对象数据成员hour,代码如下:

int main(){
	Timer t1;
	int *ph;
    // 指向Timer对象数据成员hour
	ph = &t1.hour;
    // 输出ph指针指向的地址
	cout <<"hour:" <<ph <<endl;
    // 输出ph指针指向数据成员变量值
	cout <<"hour:" <<*ph <<endl;
	return 0;
}

        从运行结果上可以看出,现在所输出的ph是指向Timer成员变量hour的地址,通过*ph则可以得到该成员变量的值,如下图:

        定义指向普通函数的指针变量方法的形式:

数据类型名 (*指针变量名)(参数列表)

        这里定义一个普通函数,并通过指针指向它,代码如下:

#include <iostream>
using namespace std;

void sortArray(int arr[], int size){
	cout <<"Array:" <<&arr <<", size:" <<size <<endl;
}

int main(){
	// 声明p指向void型函数的指针变量
	void (*p)(int arr[], int size);
	// 将 sortArray函数的入口地址赋给指针变量p
	p = sortArray;
	// 定义参数列表数组
	int nums[3] = {2, 3, 5};
	// 调用sortArray函数
	(*p)(nums, 3);
	return 0;
}

        输出结果如下图:

        而定义一个指向对象成员函数的指针变量则比较复杂一些,和定义指向普通函数的指针变量有所不同。编译系统要求在上面的赋值语句中,指针变量的类型必须与赋值好右侧函数的类型相匹配,主要以下三个方法:

  1. 函数参数的类型和参数个数;
  2. 函数返回值的类型;
  3. 所属的类;

        定义指向公用成员函数的指针变量的一般形式:

数据类型名 (类名:: *指针变量名) (参数列表)

        使指针变量指向一个公用成员函数的一般形式:

指针变量名 = &类名::成员函数名

        代码示例如下:

// 定义指向Timer类公用成员函数的指针变量
void (Timer::*ps)();
// 指针变量指向Timer类公用成员函数show_time
ps = &Timer::show_time;
// 调用对象t1中ps指向的成员函数
(t1.*ps)();

        运行结果如下:

        其实,以上定义成员函数指针变量同时,可以直接赋值Timer类成员函数址地,其得到结果是一样的。代码如下 :

// 定义指向Timer类公用成员函数的指针变量,并且指针变量指向Timer类公用成员函数show_time
void (Timer::*ps)() = &Timer::show_time;
// 调用对象t1中ps指向的成员函数
(t1.*ps)();

        成员函数不是存放在对象的空间中,而是存放在对象外的空间中,如果多个同类的对象,它们是可以共用同一个函数代码段。因此,赋给变量ps的是这个公用的函数代码段的入口地址。

三、对象数组的指针

        在C++中,处理数组和指向数组的指针时,可以通过“引用”或“指针”到数组的方式。在上一篇中获取对象数组长度时,也讲到对象数组相关内容。

址地:C++面向对象程序设计 - 数组与sizeof、对象指针使用-CSDN博客

       先通过一段代码了解下:

int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *ref = arr;
// 或 
int (*ref)[10] = &arr;        //通过指针方式
// 或
int (&ref)[10] = arr;         //通过引用方式

        1、 ref是一个指向整数的指针,当把数组arr赋值给ref时,arr会自动转换为指向数组第一个元素的指针(即&arr[0])。现在ref指向数组的第一个元素,即整数值1.可以通过解引用ref或者进行指针算术来访问数组其他元素。示例代码如下:

#include <iostream>
using namespace std;

int main(){
	int arr[10] = {1, 5, 3, 4, 5, 6, 7, 8, 9, 10};
	int *ref = arr;
	cout <<"first value:" <<*ref <<endl;
	ref++;
	cout <<"seocnd value:" <<*ref <<endl;
	return 0;
}

       运行结果可以看出当指针移到下个位置时,则对接数组arr第二个元素(即&arr[1]),如下图:

        2、 *ref 是一个指向含有10个整数的数组的指针;&arr取得了整个数组arr地址并将它赋值给ref来初始化它;可以通过解引用ref得到整个数组,而不仅仅是数组第一个元素。示例代码如下 :

#include <iostream>
using namespace std;

int main(){
	int arr[10] = {1, 5, 3, 4, 5, 6, 7, 8, 9, 10};
	int (*ref)[10] = &arr; 
	cout <<"first value:" <<(*ref)[0] <<endl;
	cout <<"seocnd value:" <<(*ref)[1] <<endl;
	return 0;
}

        以上代码可以看出,这里ref不再指向某个子元素,而是整个数组arr,所以需要通过索引进行取值。结果如下图:

        3、 &ref实际上是一个数组的引用,而不是指针。arr是数组的名称,它是数组本身的引用,所以ref是数组arr的一个别名,他们指向相同的内存位置,这里的ref也能直接访问数组的元素。示例代码如下:

#include <iostream>
using namespace std;

int main(){
	int arr[10] = {1, 5, 3, 4, 5, 6, 7, 8, 9, 10};
	int (&ref)[10] = arr;
	cout <<"first value:" <<ref[0] <<endl;
	cout <<"seocnd value:" <<ref[1] <<endl;
	return 0;
}

        这里ref只是数组arr的一个别名,所以从代码中可以看出,直接使用ref取值即可。结果如下图:

        在大多数情况下,数组的引用和指向数组的指针,在用法上很相似,但它们在类型上是有区别的。指针是一个变量,可以指向不同的地址。而引用则是一别名,必须在声明时初始化,不能重新绑定到另一个对象。

四、this指针

        每个成员函数中都包含一个特殊的指针,这个指针名是固定的,称为this。它是指向本类对象的指针,它可以调用本类中成员。this指针是隐式使用的,它是作为参数被传递给成员函数的。

        之前创建对象,定义构造函数时,形参都是以缩写方式声明的,如与成员变量一致,编译系统会直接报错。有人可能在想,就是想使用全称来声明形参,则可以通过显示使用this指针,解决这一问题。代码如下:

class Timer{
	public:
		int hour;
		int minute;
		int second;
		// this指针使用 -> 运算符调用成员
		Timer(){
			this->hour = 0;
			this->minute = 0;
			this->second = 0;
		}
		// *this指针通过点调用成员
		Timer(int hour, int minute, int second){
			(*this).hour = hour;
			(*this).minute = minute;
			(*this).second = second;
		}
		void show_time(){
			cout <<hour <<':' <<minute <<':' <<second <<endl;
		}
};

        此时编译程序,则不会报错了。以上代码中无参构造函数中直接使用 -> 运算符调用成员变量,和有参构造函数中*this通过点调用成员变量方式,在“一、指向对象的指针”中已说明,这里不再阐述。

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

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

相关文章

C++——栈和队列容器

前言&#xff1a;这篇文章我们将栈和队列两个容器放在一起进行分享&#xff0c;因为这两个要分享的知识较少&#xff0c;而且两者在结构上有很多相似之处&#xff0c;比如栈只能在栈顶操作&#xff0c;队列只能在队头和队尾操作。 不同于前边所分享的三种容器&#xff0c;这篇…

文件的随机读写--fseek,ftell,拷贝文件

想要查看fseek&#xff0c;ftell&#xff0c;函数&#xff0c;请登录这个网站&#xff1a; cplusplus.com - The C Resources Networkhttps://legacy.cplusplus.com/ 还有一个函数没有写出来&#xff0c;是rewind&#xff0c;它是&#xff1a;让⽂件指针的位置回到⽂件的起始位…

[WIP]Sora相关工作汇总VQGAN、MAGVIT、VideoPoet

视觉任务相对语言任务种类较多(detection, grounding, etc.)、粒度不同 (object-level, patch-level, pixel-level, etc.)&#xff0c;且部分任务差异较大&#xff0c;利用Tokenizer核心则为如何把其他模态映射到language space&#xff0c;并能让语言模型更好理解不同的视觉任…

图片总丢?为何不自己搭建一个图床服务

图片总丢?为何不自己搭建一个图床服务 经常写博客或者Markdown文章的同学都知道,图片资源总莫名其妙丢了,我们或者每次把图片随着md文件移过来换过去,或者找一个提供图床服务的产品,又或者扔到自己的服务器,然后将资源目录发布出来。 但是,这些方法总归存在一些问题,…

【数据结构与算法】力扣 206. 反转链表

题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a; head [1,2,3,4,5] 输出&#xff1a; [5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a; head [1,2] 输出&#xff1a; [2,1]示例 3&#…

浏览器中的桌面环境daedalOS

什么是 daedalOS &#xff1f; daedalOS 是一款 Web 桌面操作系统环境&#xff0c;但采用了与 GNOME 和 KDE 等传统桌面环境不同的方法。daedalOS 使用 JavaScript 和 TypeScript 编写&#xff0c;能够运行 dos 程序和 16/32 位 windows 程序。daedalOS 创建了一个基于网络的桌…

深入理解计算机系统 家庭作业 2.90

查一下书本的82页图2-36的表就行了 float u2f(unsigned u) {return *(float *) &u; }float fpwr2(int x) {unsigned exp, frac;unsigned u;// 小于最小的非规格化数if (x < -149) {exp 0;frac 0;}// 非规格化数else if (x < -126) {exp 0;frac 1 << (x 1…

LabVIEW深度学习

目录 一、配置环境1.1、显卡选择1.2、下载显卡驱动1.3、下载并安装Anaconda1.4、配置Anaconda软件包下载服务器1.5、配置虚拟环境tf_gpu1.6、安装vscode1.7、安装tensorflow1.8、下载安装Git1.9、安装TensorFlow Object Detection API框架1.10、安装依赖的python软件包1.11、配…

【数据结构与算法】:直接插入排序和希尔排序

1. 排序的概念及其意义 1.1 排序的概念 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 1.2 排序的稳定性 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若…

08 Python进阶:XML 解析

什么是 XML&#xff1f; XML&#xff08;可扩展标记语言&#xff0c;Extensible Markup Language&#xff09;是一种用于表示和传输数据的标记语言。它被设计用来以一种结构化的形式描述文档的内容&#xff0c;并且具有良好的跨平台和跨语言的特性。XML使用标签来定义数据的结构…

关于 elf loader 的编写

可以使用如下命令观看 elf 文件的信息 readelf -a build/ramdisk.img | vim -在编写 elf loader 的时候&#xff0c;实际上只有下图这一部分 “Program Headers” 是有用的 凡是类型为 “LOAD” 的就是需要加载进内存的部分 所以&#xff0c;只要把这些部分加载进内存里&…

晶核2024搬砖职业推荐!

在晶核手游的广袤世界中&#xff0c;选择一位适合自己的搬砖角色是每位玩家都必须认真考虑的事情。不同的职业拥有独特的技能和特点&#xff0c;能够在搬砖过程中发挥不同的优势。下面&#xff0c;我们将深入探讨晶核搬砖的四大利器&#xff0c;让你对每个角色有更深入的了解&a…

Mac苹果电脑air/pro包含m1~m3打开app显示弹框“xxx”已损坏,无法打开。您应该将它移到废纸篓

应该是保姆级教程了&#xff1a; Mac苹果电脑air/pro包含m1~m3打开app显示弹框“xxx”已损坏&#xff0c;无法打开。您应该将它移到废纸篓。 我下载的是 Sublime Text 3 for Mac中文直装版&#xff0c;https://www.32r.com/soft/38404.html 安装后打开就gg了&#xff1a; 表现…

计算机中数的表示

0. 简介 介绍计算机中数的表示方法&#xff0c;主要内容来自 c s a p p csapp csapp。 1. 整数的表示 包括有符号整数与无符号整数的表示。 假设 w → [ w n − 1 w n − 2 . . . w 0 ] \overrightarrow w[w_{n-1}w_{n-2}...w_0] w [wn−1​wn−2​...w0​] 为一种整数。…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

windows下部署mongoDB

目录 1. 下载zip安装包并解压&#xff1a;Download MongoDB Community Server | MongoDB 2. 在解压后的文件夹中新建文件夹data及下级文件夹db和log 3. 新建一个mongod.cfg文件&#xff0c;并配置以下内容 4. 在cmd中启动mongodb&#xff0c;并进行验证 5. 部署到本地服务器…

亚信安慧AntDB:打造智慧生态的数据心脏

AntDB的“融合实时”的特性&#xff0c;不仅使得数据库具备了更强大的适应性&#xff0c;更让企业在不同业务场景下能够更好地实现业务目标&#xff0c;释放出更大的商业价值。融合实时的特性让AntDB具有了高度灵活性和实时性&#xff0c;使其能够满足企业在不同业务需求下的快…

2024 批量下载公众号文章内容/阅读数/在看数/点赞数/留言数/粉丝数导出pdf文章备份(带留言):公众号混知近2000篇历史文章在线查看,找文章方便了

关于公众号文章批量下载&#xff0c;我之前写过很多文章&#xff1a; 视频更新版&#xff1a;批量下载公众号文章内容/话题/图片/封面/音频/视频&#xff0c;导出html&#xff0c;pdf&#xff0c;excel包含阅读数/点赞数/留言数 2021陶博士2006/caoz的梦呓/刘备我祖/六神读金…

uni-app如何实现高性能

这篇文章主要讲解uni-app如何实现高性能的问题&#xff1f; 什么是uni-app&#xff1f; 简单说一下什么是uni-app&#xff0c;uni-app是继承自vue.js&#xff0c;对vue做了轻度定制&#xff0c;并且实现了完整的组件化开发&#xff0c;并且支持多端发布的一种架构&#xff0c…

【Java EE】初识Spring Web MVC

文章目录 &#x1f334;什么是Spring Web MVC&#xff1f;&#x1f338;什么是Servlet呢? &#x1f332;MVC 定义&#x1f338;再理解Spring MVC &#x1f333;如何学习Spring MVC呢&#xff1f;⭕总结 &#x1f334;什么是Spring Web MVC&#xff1f; Spring Web MVC 是基于…