news 2026/9/28 3:10:20

this指针的认识+使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
this指针的认识+使用

关于C++的this指针学习总结

  • 需要回答的问题
  • this指针的认识
  • this指针的本质(一句话总结)
    • this的类型
    • this的存储位置
  • this指针的作用
    • 1.区分同名变量
    • 2.链式调用/连续赋值/连续调用(return *this)
    • 3.访问当前对象的地址或成员
  • this指针的使用(this指针与const的关系)
    • 系统运行时,会做以下的事情:
    • 常方法
    • const 与 static 的关系
    • this可以为nullptr吗?
    • this 和智能指针有什么关系?
    • 为什么不能在构造函数里调用虚函数并期望多态?
    • this和智能指针有什么关系?
    • const 与 friend

需要回答的问题

  • this指针是什么?
  • this存在哪里?
  • 编译器怎么传递this?
  • const成员函数里this是什么类型?
  • this能为空吗?
  • 为什么要用this指针?
  • 静态函数为什么没有this指针?
    …

参考链接(整合了一下自己的理解和原文中更凝练的总结)
链接: 卡码笔记this指针原理

this指针的认识

首先,我们知道对象是属性和方法的集合,但如果每次创建对象时,都为其开辟属性+方法的内存,会消耗不必要的内存空间。

eg :这里有相同类型的三个不同对象 a,b,c,属性不同但方法相同,若给每个对象都创建专属方法,会消耗对应的内存,但因为方法相同,可以共用同一套方法,进而节省空间,如下图。

这样做虽然节省了空间,但是方法无法区分调动的是a,b,c哪个对象的属性,所以为了其区分对象属性,需要将对象的地址传入,进而需要用到this指针。

代码展示

#include <iostream> using namepsace std; class Test { int num; public: Test(int x):num(x){} void Print() { cout << this << endl; } //打印this指针 }; int main() { Test a(1), b(2), c(3); cout << "&a=" << &a << endl; //打印a的地址 cout << "&b=" << &b << endl; //打印b的地址 cout << "&c=" << &c << endl; //打印c的地址 a.Print(); b.Print(); c.Print(); return 0; }

运行结果 可以看到分为这样结果的三组 表明对象地址和this打印结果相同

总结:
this指针指向调用该函数的对象
this指针存在的根本意义是为了节约空间

this指针的本质(一句话总结)

this指针是编译器隐式传给非静态成员函数的第一个参数,类型是指针常量Type* const。调用obj.func(x)时,编译器实际生成的是fun(&obj,x),把对象的地址作为第一个实参传入。this通常通过寄存器传递(x86用ecx,即thiscall约定),不占用栈空间。const成员函数的this类型就是const Type* const,所以不能修改其成员。静态成员函数无this,因为它不绑定任何对象实例。

this的类型

普通成员中:this类型是T* const,也就是指针常量,所谓指针常量就是本质是一个常量,限制的是指针,所以this的指向无法指向其他对象,但指向的对象不是常量(可以修改成员);

const成员函数中:this类型变成const T* const,指针本身不可变,指向的对象也不可变。所以无法通过this修改任何非mutable成员。

this的存储位置

this是函数参数,具体存在哪取决于调用约定。x86平台的thiscall约定中,this通过ecx寄存器传递,不占栈空间。x64和ARM平台也通常用寄存器传递前几个参数。只有在函数内部需要取this的地址时,编译器才会把它溢出到栈上。

平台寄存器
x86ecx
x64rdi / rcx
ARMr0

this指针的作用

1.区分同名变量

示例:

class Test { int num; public: Test(int num) :num(num) { //构造函数 num =100; cout << "num= " << num <<" ,"; cout <<"this->num= " << this->num << endl; } void Print( ) { //无参打印函数 int num = 100; num = num; cout << "num= " << num << " ,"; cout << "this->num= " << this->num << endl; } void Print(int num) { //有参打印函数 num = num; cout << "num= " << num << " ,"; cout << "this->num= " << this->num << endl; } }; int main() { Test t1(10); t1.Print(); t1.Print(100); return 0; }

运行结果如下:

可以看到三个函数体内有关打印的代码一致,先打印局部变量num,再打印成员变量num
第1行对应构造函数的结果 num=100 this->num =10
第2行对应有参打印函数的结果 num=100 this->num =10
第3行对应无参打印函数的结果 num=100 this->num =10
则在函数体中 num=100,num=num 其实都是对局部变量的改变,
即num=100,是对局部变量的值进行修改
num=num,是局部变量给自身赋值

由此可知:

  1. 在构造函数中初始化列表的num,系统可以区分同名的成员变量和局部变量,并正确赋值,也就是说num(num) 本质上等价于 this->num = num。
  2. 在打印函数和构造函数体中,不论是形参名还是变量名,只要与成员变量名相同,必须用this指针来和成员变量区分,否则系统会优先选择局部变量而不是成员变量。
  3. 若函数体中不存在和成员变量名相同的局部变量,则系统可以正常识别成员变量

2.链式调用/连续赋值/连续调用(return *this)

解引用 this 得到当前对象本身(类型是 T&),返回它就是返回对象的引用。链式调用 obj.set(1).set(2).set(3) 就是靠每个方法 return *this 实现的——每次返回的都是同一个对象的引用,所以可以继续调用它的方法。

在重载赋值函数中常见,代码如下:

class Test { int num; public: Test(int num) :num(num) { } Test& operator=(const Test& t) { //重载赋值函数 if (this != &t) { num = t.num; } return *this; } void Print() { cout << num << endl; } }; int main() { Test t1(10); Test t2 = t1; t1.Print(); t2.Print(); return 0; }

运行结果如下:

这里的Test t2= t2 相当于得到 t2.operaor=(t1)的返回值
这里返回类型为Test&搭配*this 可以更高效的返回对象本身

3.访问当前对象的地址或成员

这里比较好理解,用最简单的方法呈现一下:

class Test { int num; public: Test(int num) :num(num) { cout << "this= " << this; cout << " this->num= " << this->num << endl; } }; int main() { Test t1(10); return 0; }

结果如下:

this指针的使用(this指针与const的关系)

除了知道this指针上述三个作用外,还需要知道系统是如何去使用this指针,进而理解this指针与const的关系。
首先要始终牢记,this指针指向对象,再去解释后面的内容。

系统运行时,会做以下的事情:

  1. 识别类内的属性,包括:value(值) int(类型) private(访问类型)
  2. 识别类内的方法的声明(暂时不看方法体)
  3. 改写 即编译时添加形参 返回值 添加this指针
  4. 修改调用 传入this指针

示例如下:

class Test{ int value; public: void SetValue(int x) { value = x; } //改写为 //void SetValue(Test* const this,int x){this->value = x;} int GetValue() { return value; } //改写为 //int GetValue(Test* const this){return this->value;} }; int main() { Test t1; t1.SetValue(200); //修改为 t1.SetValue(&t1,200); cout << t1.GetValue() << endl; //修改为 t1.GetValue(&t1); return 0; }

系统去改写就是为了传入当前对象的地址,值得注意的时这里系统还加入了const
如void SetValue(Test* const this,int x),是为了防止在函数体中对this本身进行修改,如this=nullptr等改变this指向的操作,确保了代码的正确与安全。

常方法

系统传入this指针时,会自己加入const ,如Test* const this,
有时我们还会自己定义常方法,在函数名末尾加const

示例:

class Test{ int value; public: void SetValue(int x) { value = x; } int GetValue() const { return value; } //改写为 //int GetValue(const Test* const this){return this->value;} }; int main() { Test t1; t1.SetValue(200); cout << t1.GetValue() << endl; return 0; }

这里让 GetValue 变为常方法 int GetValue() const
加入该 const 后,系统在改写时还会对this指针再加一个const修饰
改写为:int SetValue(const Test* const this,int x),让this指针变成只读指针,无法修改this的指向,也无法修改this本身,从而实现常方法。

注意:

  1. 常对象只能调用常方法 普通函数都可以调用
  2. int fun(); int fun()const; const可以作为函数重载的依据,因为有const所以形参列表不同
  3. 同名同返回值的普通函数和常方法 普通对象优先调用普通方法 常对象调用常方法
  4. 对于不修改对象属性值的方法,让其定义或重载为常方法,可以提高代码灵活性

const 与 static 的关系

1.常方法与静态变量之间的关系
示例:

class Test { int value; static int num; public: void fun() const { cout << ++num << endl; } }; int Test::num = 0; int main() { Test t1; t1.fun(); return 0; }

运行结果为1

静态变量不为某个对象所有,是为整个类型服务的,总共只有一份
静态变量也就不受制与 this 指针,而常方法修饰的是this指针,所以代码正常运行,num结果+1。

2.静态方法与const的关系
静态方法可以直接调用,不需要用this指针来区分
静态成员函数属于类而不属于任何对象实例,调用时不需要对象(T::staticFunc()),编译器不会传入对象地址,所以没有 this。这也是静态函数不能访问非静态成员的根本原因——没有对象地址,无法定位成员的内存位置。

class Test { int value; static int num; public: // static void fun() const { //error static void fun() { cout << num << endl; //cout << value << endl; //error } }; int Test::num = 0; int main() { Test t1; t1.fun(); return 0; }

注意:

  1. 静态方法不需要this也可以调用,系统不会添加this指针 那么也无法在函数名末添加const
  2. 静态方法无this指针,无法区分对象,也无法访问对象成员

this可以为nullptr吗?

语法上可以构造出来(((T*)nullptr)->func()),但这是未定义行为。如果 func 内部不访问任何成员变量,某些编译器下可能不崩溃,但这纯属巧合,不能依赖。任何通过空 this 访问成员的操作都会段错误。

this 和智能指针有什么关系?

this 是裸指针,不管理生命周期。如果需要在对象内部获取指向自身的 shared_ptr,不能直接 shared_ptr(this)(会导致双重释放),必须继承 std::enable_shared_from_this,然后调用 shared_from_this()。

为什么不能在构造函数里调用虚函数并期望多态?

构造函数执行时,对象的动态类型还是当前正在构造的类(vptr 指向当前类的 vtable),this 的静态类型也是当前类。所以即使调用虚函数,也只会调到当前类的版本,不会调到派生类的重写版本。

this和智能指针有什么关系?

this是裸指针,不管理生命周期。如果需要在对象内部获取指向自身的shared_ptr,不能直接shared_ptr(this) 会导致双重释放,必须寂静城std::enable_shared_from_this,然后调用shared_from_this()。

const 与 friend

友元函数 属于外部函数

class Test { int value; public: Test(int x):value(x){} friend void fun(const Test& b); }; void fun(const Test& b) {cout << b.value << endl;} int main() { Test t1(10); fun(t1); return 0; }

友元函数,无this指针,也不自动添加,无法用const修饰

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 3:09:41

Sphinx 集成 Markdown:基于 MyST-Parser 的 Markdown 文档构建实战指南

文档开发工具 【免费下载链接】sphinx The Sphinx documentation generator 项目地址&#xff1a; https://gitcode.com/gh_mirrors/sp/sphinx 点击查看 免费下载 本篇指南围绕 Sphinx 项目中的 Markdown 支持展开&#xff0c;讲解如何通过 MyST-Parser 扩展让 Sphinx 直接解析…

作者头像 李华
网站建设 2026/9/28 3:09:27

Jetson Orin实战:为宇树Go2部署YOLOv5目标检测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 3:06:19

YOLO26改进 - C3k2 | C3k2融合LWGA轻量分组注意力(Light-Weight Grouped Attention):四路径并行架构破解通道冗余难题 | AAAI 2026

前言 本文介绍了轻量级骨干网LWGANet及其核心模块LWGA在YOLO26中的结合。现有用于遥感(RS)视觉质量分析的轻量级神经网络存在空间初始冗余和通道冗余问题,无法应对RS场景挑战。LWGA采用异构分组策略,将通道划分为4个不重叠子集,每个子集对应特定特征尺度,通过专用子模块…

作者头像 李华