IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> C++知识点-this指针 -> 正文阅读

[数据结构与算法]C++知识点-this指针


熟悉面向对象语言的读者一定对于 this 这个关键字很熟悉,比如Java中就有这一关键字,C++中也有,作用也和Java中的差不多。在这里我们简单介绍其概念和用法。

基本概念

The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions don’t have a this pointer.

注意以下几点:

  • this 指针不是类的一部分,它不会影响 sizeof 语句的结果。
  • this 指针用来指向调用非静态成员函数的对象(this被作为隐藏参数传递给非静态成员函数),当非静态成员函数被调用时,编译器会将该对象的地址作为隐藏参数传递给函数,为了理解这个概念我们可以看以下代码。
  • ‘this’ pointer is not available in static member functions as static member functions can be called without any object (with class name).this指针在静态成员函数中是不可用的,因为静态成员函数不能用任何对象名调用。
myDate.setMonth( 3 );

上述调用语句相当于

setMonth( &myDate, 3 );

所以我们在成员函数中使用成员变量有以下三种方法

void Date::setMonth( int mn )
{
   month = mn;            // These three statements
   this->month = mn;      // are equivalent
   (*this).month = mn;
}

我们如果往深入想,为什么编译器会默认给成员函数传递 this 指针,这里引用一段GeeksforGeeks的相关内容。

To understand ‘this’ pointer, it is important to know how objects look at functions and data members of a class.

  • Each object gets its own copy of the data member.
  • All-access the same function definition as present in the code segment.

这里解释一下:**每个类都可以有多个对象,而每个对象都有各自的成员变量,彼此是独立的。而成员函数缺失所有对象共用的,即成员函数默认是内联的。那么当在成员函数中对成员变量进行操作时,CPU怎么知道要对那个对象的变量进行操作呢,因此这里的解决办法是,编译器默认将对象的地址传递给函数,这样就解决问题了。**编译器真是又当爹又当妈,一个人默默承担了所有,只为让程序员写代码写得爽。
到这里我们也就能理解 setMonth( &myDate, 3 ); 的真正含义了。

基本用法

注意点:this是不可变的,不能对其赋值。this的基本用法笔者总结下来有以下几点

  • 返回对象本身 return *this
  • 防止自我调用 if (&Obj != this)
    可以通过以下代码示例来了解上述用法
// this_pointer.cpp
// compile with: /EHsc

#include <iostream>
#include <string.h>

using namespace std;

class Buf
{
public:
    Buf( char* szBuffer, size_t sizeOfBuffer );
    Buf& operator=( const Buf & );
    void Display() { cout << buffer << endl; }

private:
    char*   buffer;
    size_t  sizeOfBuffer;
};

Buf::Buf( char* szBuffer, size_t sizeOfBuffer )
{
    sizeOfBuffer++; // account for a NULL terminator

    buffer = new char[ sizeOfBuffer ];
    if (buffer)
    {
        strcpy_s( buffer, sizeOfBuffer, szBuffer );
        sizeOfBuffer = sizeOfBuffer;
    }
}

Buf& Buf::operator=( const Buf &otherbuf )
{
    if( &otherbuf != this )
    {
        if (buffer)
            delete [] buffer;

        sizeOfBuffer =  strlen( otherbuf.buffer ) + 1;
        buffer = new char[sizeOfBuffer];
        strcpy_s( buffer, sizeOfBuffer, otherbuf.buffer );
    }
    return *this;
}

int main()
{
    Buf myBuf( "my buffer", 10 );
    Buf yourBuf( "your buffer", 12 );

    // Display 'my buffer'
    myBuf.Display();

    // assignment operator
    myBuf = yourBuf;

    // Display 'your buffer'
    myBuf.Display();
}

注意点

为了加深理解,我们这里可以打印出this的值,可以看出其确实指向来对象的地址。

#include <iostream>

using namespace std;
class A {
    int x;
public:
    void show() {
        cout << this << endl;
    }
};

class B {};
class C {
    char c;
};

int main() {
    A *a1 = new A();
    A *a2 = new A();
    a1->show();
    cout << a1 << endl;
    a2->show();
    cout << a2 << endl;
    cout << sizeof(B) << endl; // 1
    cout << sizeof(C) << endl; // 1
    return 0;
}

output

0x7f8f86405a10
0x7f8f86405a10
0x7f8f86405a20
0x7f8f86405a20
1
1

另外,我们还想要注意:

  • this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。
  • this 只能在成员函数内部使用,用在其他地方没有意义,也是非法的。
  • 只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用。

我们可以用以下代码来测试上述结论。
code1


#include<iostream>
using namespace std;
  
class Test
{
private:
  int x;
public:
  Test(int x = 0) { this->x = x; }
  void change(Test *t) { this = t; }
  void print() { cout << "x = " << x << endl; }
};
  
int main()
{
  Test obj(5);
  Test *ptr = new Test (10);
  obj.change(ptr);
  obj.print();
  return 0;
}

上述代码会因为this->x = x编译失败,因为不能this指针不能被修改过。

code2

#include<iostream>

using namespace std;

class Test {
private:
    int x;
    int y;
public:
    Test(int x = 0, int y = 0) {
        this->x = x;
        this->y = y;
    }
    static void fun1() { cout << "Inside fun1()"; }
    static void fun2() {
        cout << "Inside fun2()";
        this->fun1(); // Error invalid use of 'this' outside of a non-static member function
    }
};

int main() {
    Test obj;
    obj.fun2();
    return 0;
}

以上代码也会编译失败,因为不能在静态成员函数中使用 this。

code3

#include<iostream>
using namespace std;

class Test {
private:
    int x;
    int y;
public:
    Test (int x = 0, int y = 0) { this->x = x; this->y = y; }
    Test setX(int a) { x = a; return *this; }
    Test setY(int b) { y = b; return *this; }
    void print() { cout << "x = " << x << " y = " << y << endl; }
};

class B {
private:
    int x;
    int y;
public:
    B(int x = 0, int y = 0) { this->x = x; this->y = y; }
    B& setX(int a) { x = a; return *this;}
    B& setY(int b) { y = b; return *this;}
    void print() { cout << "x = " << x << " y = " << y << endl; }
};


int main() {
    Test obj1;
    obj1.setX(10).setY(20);
    obj1.print(); // x = 10 y = 0

    Test obj2;
    obj2.setX(10);
    obj2.setY(20);
    obj2.print(); // x = 10 y = 20
    cout << "===============================" << endl;

    B b1;
    b1.setX(10).setY(20);
    b1.print(); // x = 10 y = 20

    B b2;
    b2.setX(10);
    b2.setY(20);
    b2.print(); // x = 10 y = 20
    return 0;
}

运行结果在代码的注释中。上述代码涉及到this的一个重要用途:链式编程。但是我们在这里需要注意一点: **return *this 可以返回一个对象的拷贝,也可以返回一个对象的本身,这取决于函数返回体的定义。**因此我们在第一个实例中 obj1.setX(10).setY(20); 只能将obj1的x改为10,不能修改obj1.y,因为setX之后返回的是obj1的拷贝。

code4

#include<iostream>
using namespace std;

class Test {
private:
    int x;
    int y;
public:
    Test(int x = 0, int y = 0) { this->x = x; this->y = y; }
    void setX(int a) { x = a; }
    void setY(int b) { y = b; }
    void destroy() { delete this; }
    void print() { cout << "x = " << x << " y = " << y << endl; }
};

int main() {
    Test obj;
    obj.destroy(); //  error for object 0x7ffee0c81810: pointer being freed was not allocated
    obj.print();
    return 0;
}

上述代码可以编译成功,但是运行会出错,因为obj不是new的对象,所以该对象不能调用 delete this,只有new的对象才能调用 delete this。具体可以参考 Is it legal (and moral) for a member function to say delete this

Reference

  1. 《C++ Primer Plus 6th》
  2. this pointer
  3. ‘this’ pointer in C++
  4. C++ this指针详解
  5. C++day8 this指针(链式编程思想) 重要(注意看注释讲解)
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:22:22  更:2022-02-16 13:22:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:48:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码