this指针 和 常成员函数
1. this指针
-
类中的成员函数(包括构造函数,析构函数)中包含有一个隐藏的当前类类型的指针参数(
类* this
),名为this在成员函数中访问类中其他成员变量就是通过this
指针来实现的 -
对于普通成员函数,
this
指针就是指向该成员的调用对象,对于构造函数,this
指针就是指向正在创建的对象 -
Code
#include <iostream>
using namespace std;
class User{
public:
User(const string& name,const string& passwd):m_name(name),m_passwd(passwd){}
void print(void){
cout<<m_name<<","<<m_passwd<<endl;
//通过this指针访问和上面等价
cout<<this->m_name<<","<<this->m_passwd<<endl;
cout<<"&this "<<this<<endl;//看一下this是不是指向对象的一个指针
}
/*print 编译器处理后的形式,实质通过this指针来访问
void print(User* this){
cout<<this->m_name<<","<<this->m_passwd<<endl;
}
*/
private:
string m_name;
string m_passwd;
};
int main(void){
User u1("张三","123456");
User u2("李四","654321");
u1.print();//User::print(&u1);//本质会传递一个对象的指针
u2.print();//User::print(&u2);
cout<<"&u1 "<<&u1<<endl;//打印出对象的地址,会发现在对象的成员函数中this就是一个指向该对象的指针
cout<<"&u2 "<<&u2<<endl;
return 0;
}
运行结果
$ ./a.out
张三,123456
张三,123456
&this 0x7ffcc430a660
李四,654321
李四,654321
&this 0x7ffcc430a6a0
&u1 0x7ffcc430a660
&u2 0x7ffcc430a6a0
需要使用this
指针的场景
-
区分作用域
通过this
指针来区分成员变量和形参变量
当类中成员函数的形参变量和类中的成员变量的表示符相同时,直接访问该变量访问到的是形参变量,同thsi
指针来访问该变量,访问到的是类中的成员变量 -
从成员函数返回调用对象自身(重点)
从函数返回引用对象自身时,返回值的类型是当前对象的引用
类& 成员函数(){
//当前成员函数的this指针指向该函数的调用对象
//*this 就是调用对象本身
//
return *this;//返回自引用
}
#include <iostream>
using namespace std;
class Counter{
public:
Counter(int count=0):m_count(count){}
void print(void){
cout<<"计数值"<<m_count<<endl;
}
Counter& add(void){
++m_count;
//this指向add函数的调用对象
//*this就是调用对象自身
return *this;//返回自引用,返回结果调用自身
}
private:
int m_count;
};
int main(void){
Counter cn;//以无参形式创建对象
cn.add().add().add();//每次函数返回的都是调用者本身的引用,所以可以连续调用
cn.print();//计数值3
}
- 从对象内部销毁对象自身(对象自销毁函数)
将使用new
动态创建的对象的销毁过程封装到类成员函数中,通过调用某个类的成员函数来实现对象的销毁
//成员对象函数的对象自销毁函数
void destroy (void){
delete this;//this就是调用对象自身,delete的相当于new动态分配出来的对象
}
- 作为函数的实参,实现对象之间的交互(了解)
在编写代码是因遵从低内聚高耦合的原则,因此,作为函数实参来传递对象时,违背了这一原则,如果修改了某一个类,其他类也会受到影响,后期代码不好维护
#include <iostream>
//一个老师类,一个学生类,老师对象提问:什么是this指针,学生对象向老师对象回答:this指针就是指向调用对象的指针
using namespace std;
class Tea;//短视声明
class Stu{
public:
void ask(const string& q ,Tea* t);
private:
string m_answer;
};
class Tea{
public:
void educate(Stu* s);
void reply(const string& answer);
private:
string m_answer;
};
void Tea::educate(Stu *s) {
s->ask("什么是this指针?", this);
}
void Tea::reply(const string &answer) {
cout<<"回答:"<<answer<<endl;
}
void Stu::ask(const string &q, Tea *t) {
cout<<"问题:"<<q<<endl;
t->reply("this就是指向调用对象的指针");
}
int main() {
Tea t;
Stu s;
t.educate(&s);
return 0;
}
运行结果
问题:什么是this指针?
回答:this就是指向调用对象的指针
2. 常成员函数(cosntstruction)
- 常成员函数形式
在一个成员函数的参数表前添加const
修饰,该函数就是常函数,即常成员函数,常成员函数实际修饰的是this指针
class 类名{
返回值类型 函数名 const(形参表){函数体;}
};
- 常成员函数中的
this
指针具有常属性,是一个常指针,不能在常成员函数中通过this
指针来修改类中的成员变量
#include <iostream>
using namespace std;
class A{
public:
A(int data = 0):m_data(data){}
void print (void) const{//常函数
//cout << this->m_data<<endl;
//尝试在常函数中对成员变量进行修改
cout<<m_data++<<endl; //error
}
private:
int m_data;
};
int main (void){
A a(123);
a.print();
return 0;
}
$ g++ demo.cpp
demo.cpp: In member function ‘void A::print() const’:
demo.cpp:9:24: error: increment of member ‘A::m_data’ in read-only object
9 | cout<<m_data++<<endl; //error:
|
- 常成员函数中修改成员变量的两种方式
1> 使用去常转换
cosnt_case<类名*>(this)->成员变量 = 值;
2>使用mutable
修饰成员变量
- 非常对象既可以调用常函数也可以调用非常函数,但是常对象(包括常指针和常引用)只能调用常函数
常对象调用非常函数时,编译器将会编译报错,因为这是一种放大权限的操作
#include <iostream>
using namespace std;
class A{
public:
//void func1(const A* this)
void func1(void)const{
cout <<"const func"<<endl;
}
//void func2(A* this)
void func2(void){
cout <<"unconst func"<<endl;
}
};
int main (void){
A a;
a.func1();//A::func1(&a),A*
a.func2();//a::func2(&a),A*
const A a2 = a;
a2.func1();//A::func1(&a2),const A*
a2.func2();//A::func2(&2),const A*//error常对象只能调用常函数
return 0;
}
运行结果
demo.cpp: In function ‘int main()’:
demo.cpp:20:18: error: passing ‘const A’ as ‘this’ argument discards qualifiers [-fpermissive]
20 | a2.func2();//A::func2(&2),const A*//error常对象只能调用常函数
| ^
demo.cpp:10:14: note: in call to ‘void A::func2()’
10 | void func2(void){
| ^~~~~
- 类中的常成员函数只能调用常函数,不能调用非常函数
- 同一个类中函数名和形参表的函数其常版本和非常版本可以构成函数重载,常对象匹配常函数,非常对象匹配非常函数
#include <iostream>
using namespace std;
class A{
public:
void func(void)const{
cout <<"const func"<<endl;
}
void func(void){
cout <<"uncosnt func"<<endl;
}
};
int main (void){
A a1;
a1.func();//unconst
const A a2;
a2.func();//const
const A a3 = a1;
a3.func();//const
return 0;
}
运行结果
uncosnt func
const func
const func