本文章是作者根据史蒂芬·普拉达所著的《C++ Primer Plus》而整理出的读书笔记,如果您在浏览过程中发现了什么错误,烦请告知。另外,此书由浅入深,非常适合有C语言基础的人学习,感兴趣的朋友可以自行阅读此书籍。
this指针
我们在上一个文章《第10章 对象和类——对象和类(二) 类的构造函数和析构函数》的最后,完善了Student类。该类声明如下:
// student.hpp
#ifndef _STUDENT_H_
#define _STUDENT_H_
#include <string>
using namespace std;
class Student{
private:
string m_id;
string m_name;
int m_yuwen;
int m_shuxue;
int m_yingyu;
int m_total;
int m_avr;
void set_total() { m_total = m_yuwen + m_shuxue + m_yingyu;}
void set_avr() { m_avr = m_total/3;}
public:
Student();
Student(const string &id, const string &name,
int yuwen = 0, int shuxue = 0, int yingyu = 0);
~Student();
void display();
};
#endif
我们可以看到,每个类成员函数都只涉及一个对象,即调用它的对象。但有时候方法可能涉及到两个对象,在这种情况下需要使用C++的this指针。
假设针对Student类有一个新的需求,需要比较两个学生的总分,然后返回总分比较大的那个学生。
我们要确认这个成员函数的原型,首先,它要返回一个对象,其次,它需要比较两个对象的总分并返回较大的那个的对象。另外,我们只是为了比较大小,并不是要去修改某个对象,因此我们需要使用const来限制修改。
我们很容易就想到了如下的原型。
const Student& getMaxObj(const Student& st) const;
关于const的说明:
- 第一个const表示我们返回一个Student对象的引用,这个对象返回之后不可被修改。
- 第二个const表示我们接收一个Student对象的引用,类方法中不可修改此对象,比如st1.getMaxObj(st2), st2就是此对象,此方法中不可修改st2的成员。
- 第三个const表示getMaxobj函数为"const成员函数",类方法中不可修改调用对象,比如st1.getMaxObj(st2),st1就是调用对象,此方法中不可修改st1的成员。
但当我们想要实现这个方法时,我们发现出现了问题:
const Student& Student::getMaxObj(const Student& st) const
{
if(st.m_total > m_total)
{
return st;
}
else
{
return ???; //此处应该返回什么?
}
}
C++解决这种问题的方法是:使用被称为this的特殊指针。this指针指向用来调用成员函数的对象(this被作为隐藏参数传递给方法)。这样的话,st1.getMaxObj(st2)将this设置为st1对象的地址,使得这个指针可用于getMaxObj方法。同样,函数调用st2.getMaxObj(st1)将this设置为st2对象的地址。
一般来说,所有的类方法都将this指针设置为调用它的对象的地址。也就是说,getMaxObj()中的m_total,其实也可以写成this->m_total。
每个成员函数(包括构造函数和析构函数)都有一个this指针。this指针指向调用对象。如果方法需要引用整个调用对象,则可以使用表达式*this。在函数的括号后面使用const限定符将this限定为const,这样将不能使用this来修改对象的值。
然而,要返回的并不是this,因为this是对象的地址,而不是对象本身,即 * this(将解除引用运算符*用于指针,将得到指针指向的值)。
this为调用对象的地址,*this即为调用对象,基于此,我们可以完成前面的定义。
const Student& Student::getMaxObj(const Student& st) const
{
if(st.m_total > m_total)
{
return st;
}
else
{
return *this; //返回当前调用对象。
}
}
我们继续完善下Student类:
// student.hpp
#ifndef _STUDENT_H_
#define _STUDENT_H_
#include <string>
using namespace std;
class Student{
private:
string m_id;
string m_name;
int m_yuwen;
int m_shuxue;
int m_yingyu;
int m_total;
int m_avr;
void set_total() { m_total = m_yuwen + m_shuxue + m_yingyu;}
void set_avr() { m_avr = m_total/3;}
public:
Student();
Student(const string &id, const string &name,
int yuwen = 0, int shuxue = 0, int yingyu = 0);
~Student();
void display() const; //显示信息不需要修改对象成员,我们将其声明为const成员函数
const Student& getMaxObj(const Student& st) const;
};
#endif
//student.cpp
#include <iostream>
#include <string>
#include "student.hpp"
using namespace std;
Student::Student()
{
m_id = "no id";
m_name = "no name";
m_yuwen = 0;
m_shuxue = 0;
m_yingyu = 0;
m_total = 0;
m_avr = 0;
cout << "create obj: " << this->m_name << endl;
}
Student::~Student()
{
cout << "delete obj: " << this->m_name << endl;
}
Student::Student(const string &id, const string &name, int yuwen, int shuxue, int yingyu)
{
m_id = id;
m_name = name;
m_yuwen = yuwen;
m_shuxue = shuxue;
m_yingyu = yingyu;
set_total();
set_avr();
cout << "create obj: " << this->m_name << endl;
}
void Student::display() const
{
cout << "show info: " << endl;
cout << m_id << " " << m_name << endl
<< "yuwen: " << m_yuwen << endl
<< "shuxue: " << m_shuxue << endl
<< "yingyu: " << m_yingyu<< endl
<< "total : " << m_total << endl
<< "avr : " << m_avr << endl;
}
const Student& Student::getMaxObj(const Student& st) const
{
if(st.m_total > m_total)
{
return st;
}
else
{
return *this;
}
}
我们可以使用如下的方式来使用:
//student_main.cpp
#include <iostream>
#include "student.hpp"
using namespace std;
int main()
{
const Student st1 = Student("00001", "wangdamao", 89,98,83);
const Student st2 = Student("00002", "wangxiaoming", 89,89,97);
st1.getMaxObj(st2).display();
return 0;
}
st1.getMaxObj(st2).display(),我们先通过st1的getMaxobj()方法得到了一个总分较大的对象,该对象也是Student类对象,因此可以调用display()方法。