当前位置: 首页 > news >正文

C++ this指针与静态属性的关系

关于静态的说明:

1.类中的静态成员是所有对象共享的,所以不能在静态方法里面访问非静态元素
2.类中的非静态成员,可以访问类的静态成员和类的非静态成员


C++内存的分配方式

要想理解this指针和静态属性的关系,需要先了解C++内存的分配方式

一个由C/C++编译程序占用内存分为以下几个部分:

栈区(stack) : 由编译器自动分配和释放,存放 函数参数值,局部变量值,返回地址等。操作方式类似于数据结构中的 栈 。栈内存分配时的运算 内置于处理器指令集中, 效率很高但分配内存的容量有限(VC6下,默认的栈空间大小为1M)

堆区(heap) : 一般 由程序员进行分配和释放 ,亦称动态的内存分配,如果程序员不进行释放,程序结束时可能由OS回收,程序在运行时用mallocnew申请任意多少的内存,程序员自己负责在何时用freedelete释放内存。 动态内存生存周期由我们决定,使用非常灵活但问题繁多 ,与数据结构中的 堆 是两个概念,分配方式类似于链表(32位系统下,堆内存空间可以达到4G)

全局区(静态区)(static) : 全局变量和静态变量存储是存放在一块的,初始化过的全局变量和静态变量为一个区域,未进行初始化的全局变量和静态变量在另一块相邻的区域.全局区的内存在程序结束后由系统释放 (初始化过的变量释放到data区,未初始化的变量分配到bbs区)

文字常量区 : 常量字符串就是放在这里,程序结束后由系统释放到coment区

程序代码区 : 存放函数体二进制代码,存放在code区


this指针

回顾一下什么是this指针:
this指针是类的一个自动生成的并自动隐藏私有成员(privite),它存在于类的非静态成员函数,this指针指向被调用函数所在的对象的地址

也就是说,当一个对象被创建,该对象内便会自动生成一个this指针成员,其为私有成员且自动隐藏,生成后便自动指向对象数据的首地址


为了证明this指针是指向对象数据的首地址,用以下程序进行说明

#include <iostream>
#include <string>

using namespace std;

class Point
{
private:
	static int count;//todo定义访问权限为私有的静态变量count
	int x, y;
	static int staticnum;//类内声明静态变量
public:
	Point(int a, int b)//todo构造函数
	{
		count++;//todo每构建一个对象就会调用构造函数,count这个静态变量也会自增
		cout<<"第"<<count<<"个对象的this指针地址为" << this << endl;//todo打印this指针(对象的地址 只能放入类和类的成员函数中) 
		x = a;
		y = b;
	}
	void MovePoint(int a, int b)
	{
		x = a;
		y = b;
	}
	void print()
	{	
		cout << "x为:" << x << "          y为:" << y << endl;
	}
};
//🌟类外声明静态变量 (要使用静态变量和静态成员函数 必须分配内存和初始化)
int Point::count = 0;
int Point::staticnum=0;

int main()
{	
	
	Point point1(10, 10);
	point1.print();
	cout << "对象的地址为" <<&point1 << endl;//todo打印对象的地址
	point1.MovePoint(2, 2);
	//todo当对象point1调用Movepoint(2,2)这个函数时,即将point1对象的地址传递给了this指针
	//Movepoint(2,2)这个函数的原型应该是void Movepoint(Point this*,int a,int b);
	//todo第一个参数时指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的
	//这样point1的地址传递给了this指针,所以在MovePoint函数中便可以显示的写成:void MovePoint(int a,int b){this->x=a;this->y=b;}
	//todo即可知道,point1调用该函数后,也就是point1的数据成员被调用并更新了值

	point1.print();


	//todo在任何一个方法里都可以使用this指针。C++对象是一种特殊的结构 是除了变量还包含一些函数的特殊结构
	//程序运行时,对象的属性(变量)和方法(函数)都是保存在内存里,这就意味着它们各自都有与之相关联的地址
	//todo这些地址都可以通过指针来进行访问,而this指针一定保存着对象本身的地址,每调用一个方法,this指针都会随着提供的输入参数被秘密的传递给那个方法
	//正是因为如此,我们才能在方法里像使用一个布局变量那样使用this指针

	//todo因为静态成员和静态方法不是属于某个特定的对象,而是由全体对象共享的,这就意味着它们无法访问this指针,所以,我们才无法在静态方法里访问非静态的类成员(变量和方法)
	//如果需要访问非静态的类成员 则需要this指针来访问 
	//todo在使用静态属性时,必须为它们分配内存。具体做法很简单,只要在类声明的外部对静态属性进行声明即可(类似于声明一个变量)
	
	Point point2(20, 20);
	point2.print();
	return 0;
}

当对象point1调用MovePoint(2,2)函数时,此时point对象的地址也传递给你了this这个指针,MovePoint函数的原型事实上应是:

void MovePoint(Point *this, int a, int b);

参数列表中的第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的,此时,point1的地址传递给了this,所以在MovePoint函数中便可以显式的写成:

void MovePoint(int a,int b)
{
	this->x=a;//此行意思为 point1这个对象的地址中的x的值 赋值给movePoint中的a
	this->y=b;
}

即可以知道,point1调用该函数后,也就是point1的数据成员被调用(调用值-类成员x,y) 并 更新了值(更新值-MovePoint函数中的a,b)


程序结果:

在这里插入图片描述


总结和注意:🎯

任何一个方法(包括构造器函数)都可以使用this指针获取对象的地址,从本质上讲,C++中的对象其实是一种特殊的结构(是一种除了变量还包含函数的特殊的结构)

在程序正在运行时,对象的属性(变量)和方法(函数)都是保存在内存中,且各自都有与之相关联的地址,这些地址都可以通过指针来进行访问,而最重要的this指针保存着对象本身的地址

每调用一个方法的时候,this指针都会随着你提供的输入参数被秘密的传递给这个方法,正因为如此,我们才能在方法(成员函数)里像使用一个局部变量那样使用this指针

由于静态方法不是属于某个特定的对象,而是由全体对象共享,这就意味静态方法不可能有个固定的地址来索引某个对象,也就是说静态方法无法访问this指针,而非静态成员需要用this指针来访问自己属于的对象,这就是为什么我们无法在静态方法里访问非静态成员的原因


本文来自
C++内存分配方式详解🔍
静态属性和静态方法2以及this指针的又一些说明🔍

相关文章:

  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • C++ new和delete动态分配和释放内存
  • C++ 类对象与类指针(静态和动态多态)
  • 第六天 if if…else 三木运算符
  • C++ 虚函数与多态性
  • pb11.2build8949 数据窗口dw limit有关问题
  • VS 监视功能
  • C++ 抽象类
  • C++ 运算符重载
  • 购买Microsoft Technet订阅,免费获得微软几乎所有的产品序列号“用于评估”,...
  • C++ 操作符重载
  • 客户端调用webservice的两种方式
  • C++ 多继承
  • redmine 主题thems-默认主题
  • C++ 虚继承
  • 【EOS】Cleos基础
  • Android单元测试 - 几个重要问题
  • Angular数据绑定机制
  • AWS实战 - 利用IAM对S3做访问控制
  • C++类的相互关联
  • es6(二):字符串的扩展
  • JavaScript 奇技淫巧
  • Linux链接文件
  • magento 货币换算
  • mysql_config not found
  • React Transition Group -- Transition 组件
  • TCP拥塞控制
  • 基于axios的vue插件,让http请求更简单
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端之React实战:创建跨平台的项目架构
  • 山寨一个 Promise
  • UI设计初学者应该如何入门?
  • ​ubuntu下安装kvm虚拟机
  • #pragma once与条件编译
  • #Z2294. 打印树的直径
  • #传输# #传输数据判断#
  • (LeetCode) T14. Longest Common Prefix
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (汇总)os模块以及shutil模块对文件的操作
  • (力扣)1314.矩阵区域和
  • (强烈推荐)移动端音视频从零到上手(上)
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (转)Oracle存储过程编写经验和优化措施
  • (转)Windows2003安全设置/维护
  • (转)使用VMware vSphere标准交换机设置网络连接
  • (转载)利用webkit抓取动态网页和链接
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .apk文件,IIS不支持下载解决
  • .bat批处理出现中文乱码的情况
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET正则基础之——正则委托
  • .php结尾的域名,【php】php正则截取url中域名后的内容