我们由一个题目引入:
cpp
class Date
{
public:
void Init(int year=2024, int month=1, int day=27)
{
_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();
d1.Print();
d2.Init(2023, 10, 24);
d2.Print();
return 0;
}
面对如上代码,我想问Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个"非静态的成员函数"增加了一个隐藏
的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有"成员变量"
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成
一.this指针的特性
cpp
void Print(Date* const this)
{
cout << this->_year << "-" <<this-> _month << "-" << this->_day << endl;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//两者等价
此时我们就发现了this指针的特性:
1. this指针的类型:类型* const,即成员函数中,不能给this指针赋值。
2. 只能在"成员函数"的内部使用
3. this指针本质上是"成员函数"的形参,当对象调用成员函数时,将对象地址作为实参传递给
this形参。所以对象中不存储this指针。
4. this指针是"成员函数"第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递,不需要用户传递
注意点:
1.this指针存在于形参和实参的位置,我们是不可以认为显示的写
2.函数内部可以使用
现在大家简单能理解了this指针,现在我们以问答的方式来深入理解this指针:
1.this 存在哪里 b 因为他是一个形参?(不算放在寄存器的)
a、堆 b、栈 c、静态区 d、常量区 e、对象里面
答案是;b
解析;
首先最不能选的是e,如果this指针放对象里面,它是不是一个指针,那么肯定要占用4/8字节的空间 但是计算的时候我们是不是没有计算this指针的大小,所以排除e
a是动态开辟的空间存放的位置,c静态区是存放全局变量或static修饰的内容,所以这两个也可以排除
对于常量区我们听名字就知道常量区是指在程序运行是不发生改变的量,this指针的对象是没有被const修饰,所以可以改变,而const修饰了this指向,所以this不能改变指向,但是可以改变指向的内容,所以不存在常量区。
综上,this指针在栈区,选b。
问题2:
下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
cpp
class A
{
public:
void print()
{
cout << "print()" << endl;
}
private:
int _a;
};
int main()
{
A* ptr = nullptr;
ptr->print();
return 0;
}
结果:
所以答案选:C
解析:
我们定义了一个A类指针指向nullptr,然后执行ptr->print(),隐式传递了this指针,但是是空指针,而在我们的成员函数内部并没有涉及到this指针方面内容,所以可以正常调用,这里我们可以检查this指针是不是空:
问题三:
下面程序编译运行结果是?
A、编译报错B、运行崩溃 C、正常运行
cpp
class A
{
public:
void print()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* ptr = nullptr;
ptr->print();
return 0;
}
结果发现什么都没输出,可见程序崩了。
答案选:B
补充:(我们没有任何错误,就不可能是在编译时错误,排除A)
解析:
这题和上题区别在于我们我们成员函数与this指针息息相关了,但是该指针是指向空,所以我们我们根本访问不到类的成员变量,所以程序崩了,所以选B
问题四:
下面程序编译运行结果是?
A、编译报错B、运行崩溃 C、正常运行
cpp
class A
{
public:
void print()
{
cout << "print()" << endl;
}
private:
int _a;
};
int main()
{
A* ptr = nullptr;
(*ptr).print();
return 0;
}
选C
这题我们将前面的放在一起来分析:
我重写一段代码:
cpp
class A
{
public:
void print()
{
cout << this << endl;
cout << _a << endl;
cout << "print()" << endl;
}
private:
int _a=10;
};
int main()
{
A* ptr = nullptr;
(*ptr).print();
return 0;
}
我们发现结果是第三个cout失败导致程序崩了,所以我们的调用:(*ptr).print()理解尤为重要,这里我们可以理解为:虽然我们对ptr指针解引用了,但是我们实际问题和问题三一样。
最后,感谢大家的支持!