C++ this指针讲解

一、this指针的引出

我们先来定义一个日期类 Date

class Date
{ 
public:
 void Init(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 void Print()
 {
 cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }
private:
 int _year;     // 年
 int _month;    // 月
 int _day;      // 日
};
int main()
{
 Date d1, d2;
 d1.Init(2022,1,11);
 d2.Init(2022, 1, 12);
 d1.Print();
 d2.Print();
 return 0;
}

对于上述类,有这样的一个问题: Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,从汇编代码上看:它们的调用地址都是一样的。

	d1.Init(2022, 1, 11);
00007FF677B45ECD  mov         r9d,0Bh  
00007FF677B45ED3  mov         r8d,1  
00007FF677B45ED9  mov         edx,7E6h  
00007FF677B45EDE  lea         rcx,[d1]  
00007FF677B45EE2  call        Date::Init (07FF677B4146Ah)  
	d2.Init(2022, 1, 12);
00007FF677B45EE7  mov         r9d,0Ch  
00007FF677B45EED  mov         r8d,1  
00007FF677B45EF3  mov         edx,7E6h  
00007FF677B45EF8  lea         rcx,[d2]  
00007FF677B45EFC  call        Date::Init (07FF677B4146Ah)  
	d1.Print();
00007FF677B45F01  lea         rcx,[d1]  
00007FF677B45F05  call        Date::Print (07FF677B4146Fh)  
	d2.Print();
00007FF677B45F0A  lea         rcx,[d2]  
00007FF677B45F0E  call        Date::Print (07FF677B4146Fh) 

输出结果:

2022-1-11
2022-1-12

那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢? 

这是由于C++在这段代码中做出手脚 ,C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

在调用的时候也传的是各自的地址。这样就十分清晰明了了。这就是隐含的this指针

上面所注释的都是隐含的 this 指针 在操作。

注意:这里我们不能显示this指针所操作的写出来,因为他是隐含的,我们不能抢了编译器的活。但是我们可以直接在类里面用。 

void Print()
{
	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

 二、this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。

class MyClass {
    int value;
public:
    void modifyThis() {
        MyClass obj;
        // this = &obj;  // 错误!this 是常量指针,不能修改其指向的地址
        this->value = 10; // 合法:可以修改成员变量
    }
};

2. 只能在“成员函数”的内部使用

class MyClass {
    int value;
public:
    void validUse() {
        this->value = 10; // 合法:非静态成员函数中使用
    }

    static void staticFunc() {
        // this->value = 20; // 错误!静态函数中无 this 指针
    }
};

void globalFunc() {
    // this->value = 30; // 错误!全局函数中不能使用 this
}

3. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

4. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。 


 三练习this指针

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
 void Print()
 {
 cout << "Print()" << endl;
 }
private:
 int _a;
};
int main()
{
 A* p = nullptr;
 p->Print();
 return 0;
}

结果:C      正常运行

原因:Print()函数是存在公共代码区中,编译的时候在公共代码区中找到这个函数,和普通的函数调用是一样的,只需要call函数地址就行。这里p是空指针,传过去的this指针只是接收了p的空指针,就类似于this指针被初始化为空指针。这是允许的。

再来一题:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 int _a;
};
int main()
{
    A* p = nullptr;
    p->PrintA();
    return 0;
}

结果:B      运行崩溃

原因:这里p是空指针,传过去的this指针只是接收了p的空指针,但是在PrintA()中,会隐含一个this->_a,而this指针是一个空指针,访问this指针_a的位置,就要对this指针进行解引用,此时程序就会崩溃,因为对空指针进行了解引用。

通过两题总结:

1.this指针是可以为空的

2.this指针存储在栈里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值