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

本文详细介绍了C++中指针的基本概念,包括指向对象、对象成员、普通函数和对象成员函数的指针,以及this指针的使用。通过实例展示了如何操作和访问这些指针,以及它们在面向对象编程中的重要性。
摘要由CSDN通过智能技术生成

        在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通过点调用成员变量方式,在“一、指向对象的指针”中已说明,这里不再阐述。

  • 29
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值