C++编程学习(九)this指针&友元函数
mooc西工大魏英老师的课程通道关闭了,难受。现在边看工程代码边重温刷第一遍C++时候的知识点,顺序没有按照大纲的来,想到哪写到哪。
this是干啥用的?
简介:在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象(意味着可以访问当前对象的所有成员)。
实质:this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。
this 作为隐式形参,本质上是成员函数的局部变量,所以只能用在成员函数的内部,并且只有在通过对象调用成员函数时才给 this 赋值。
在《C++函数编译原理和成员函数的实现》一节中讲到,成员函数最终被编译成与对象无关的普通函数,除了成员变量,会丢失所有信息,所以编译时要在成员函数中添加一个额外的参数,把当前对象的首地址传入,以此来关联成员函数和成员变量。这个额外的参数,实际上就是 this,它是成员函数和成员变量关联的桥梁。
注意:友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
(问题来了,什么是友元?详见文末)
1 #include <iostream> 2 using namespace std; 3 4 class Student{ 5 public: 6 void setname(char *name); 7 void setage(int age); 8 void setscore(float score); 9 void show(); 10 private: 11 char *name; 12 int age; 13 float score; 14 }; 15 16 void Student::setname(char *name){ 17 this->name = name; 18 } 19 void Student::setage(int age){ 20 this->age = age; 21 } 22 void Student::setscore(float score){ 23 this->score = score; 24 } 25 void Student::show(){ 26 cout<<this->name<<"的年龄是"<<this->age<<",成绩是"<<this->score<<endl; 27 } 28 29 int main(){ 30 Student *pstu = new Student; 31 pstu -> setname("李华"); 32 pstu -> setage(16); 33 pstu -> setscore(96.5); 34 pstu -> show(); 35 36 return 0; 37 }
运行结果是:
1 李华的年龄是16,成绩是96.5
this 只能用在类的内部,通过 this 可以访问类的所有成员,包括 private、protected、public 属性的。
本例中成员函数的参数和成员变量重名,只能通过 this 区分。以成员函数setname(char *name)
为例,它的形参是name
,和成员变量name
重名,如果写作name = name;
这样的语句,就是给形参name
赋值,而不是给成员变量name
赋值。而写作this -> name = name;
后,=
左边的name
就是成员变量,右边的name
就是形参,一目了然。
注意,this 是一个指针,要用->
来访问成员变量或成员函数。
this 虽然用在类的内部,但是只有在对象被创建以后才会给 this 赋值,并且这个赋值的过程是编译器自动完成的,不需要用户干预,用户也不能显式地给 this 赋值。本例中,this 的值和 pstu 的值是相同的。
我们不妨来证明一下,给 Student 类添加一个成员函数printThis()
,专门用来输出 this 的值,如下所示:
1 void Student::printThis(){ 2 cout<<this<<endl; 3 } 4 //然后在 main() 函数中创建对象并调用 printThis(): 5 Student *pstu1 = new Student; 6 pstu1 -> printThis(); 7 cout<<pstu1<<endl; 8 9 Student *pstu2 = new Student; 10 pstu2 -> printThis(); 11 cout<<pstu2<<endl;
运行结果:
1 0x7b17d8 2 0x7b17d8 3 0x7b17f0 4 0x7b17f0
可以发现,this 确实指向了当前对象,而且对于不同的对象,this 的值也不一样。
几点注意:
- this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。
- this 只能在成员函数内部使用,用在其他地方没有意义,也是非法的。
- 只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用(后续会讲到 static 成员)。
什么是友元?
私有成员对于类外部的所有程序部分而言都是隐藏的,访问它们需要调用一个公共成员函数,但有时也可能会需要创建该规则的一项例外。
友元函数是一个不属于类成员的函数,但它可以访问该类的私有成员。换句话说,友元函数被视为好像是该类的一个成员。友元函数可以是常规的独立函数,也可以是其他类的成员。实际上,整个类都可以声明为另一个类的友元。
为了使一个函数或类成为另一个类的友元,必须由授予它访问权限的类来声明。类保留了它们的朋友的 "名单",只有名字出现在列表中的外部函数或类才被授予访问权限。通过将关键字 friend 放置在函数的原型之前,即可将函数声明为友元。
在 Budget 类的以下声明中,另一个类的 addBudget 函数 Aux 已声明为友元:
1 class Budget 2 { 3 private: 4 static double corpBudget; 5 double divBudget; 6 public: 7 Budget() { divBudget = 0; } 8 void addBudget(double b) 9 { 10 divBudget += b; 11 corpBudget += divBudget; 12 } 13 double getDivBudget() const { return divBudget; } 14 static double getCorpBudget() { return corpBudget; } 15 static void mainOffice(double); 16 friend void Aux::addBudget (double) ; // 友元 17 };
假设另一个 Aux 类代表一个分部的附属办公室,也许在另一个国家。附属办公室提出了一个单独的预算要求,该要求必须添加到整个企业的预算中。则 Aux::addBudget 函数的友元声明告诉编译器,该函数己授予访问 Budget 的私有成员的权限。该函数釆用 double 类型的实参,表示要添加到企业预算中的金额:
1 class Aux 2 { 3 private: 4 double auxBudget; 5 public: 6 Aux() { auxBudget =0; } 7 void addBudget(double); 8 double getDivBudget() { return auxBudget; } 9 };
以下是 Aux addBudget 成员函数的定义:
1 void Aux::addBudget(double b) 2 { 3 auxBudget += b; 4 Budget::corpBudget += auxBudget; 5 }
形参 b 被添加到企业预算中,这是通过使用表达式 Budget::corpBudget 来访问并实现的。下面的程序演示了这些类在完整程序中的用法。
1 //auxil.h的内容 2 #ifndef AUXIL_H 3 #define AUXIL_H 4 // Aux class declaration. 5 class Aux 6 { 7 private: 8 double auxBudget; 9 public: 10 Aux() { auxBudget = 0; } 11 void addBudget(double); 12 double getDivBudget() const { return auxBudget; } 13 }; 14 #endif 15 //budget3.h的内容 16 #ifndef BUDGET3_H 17 #define BUDGET3_H 18 #include "auxil.h" // For Aux class declaration 19 //Budget class declaration. 20 class Budget { 21 private: 22 static double corpBudget; 23 double divBudget; 24 public: 25 Budget() { divBudget =0; } 26 void addBudget(double b) 27 { 28 divBudget += b; 29 corpBudget += divBudget; 30 } 31 double getDivBudget() const {return divBudget;} 32 static double getCorpBudget() {return corpBudget;} 33 static void mainOffice(double); 34 friend void Aux::addBudget(double); 35 }; 36 #endif 37 38 //budget3.cpp的内容 39 #include "budget3.h" 40 //Definition of static member. 41 double Budget::corpBudget = 0; 42 void Budget:imainOffice(double budReq) 43 { 44 corpBudget += budReq; 45 } 46 47 //auxil.cpp的内容 48 #include "auxil.h" 49 #include "budget3.h" 50 void Aux::addBudget(double b) 51 { 52 auxBudget += b; 53 Budget::corpBudget += auxBudget; 54 } 55 56 //main程序的内容 57 //This program demonstrates a static class member variable. #include <iostream> 58 #include <iomanip> 59 #include "budget3.h" 60 using namespace std; 61 62 int main() 63 { 64 const int N_DIVISIONS = 4; 65 // Get the budget requests for the divisions and offices 66 cout << "Enter the main office's budget request:"; 67 double amount; 68 cin >> amount; 69 Budget:imainOffice(amount); 70 // Create the division and auxiliary offices 71 Budget divisions [N_DIVISIONS]; 72 Aux auxOffices[N_DIVISIONS]; 73 cout << "\nEnter the budget requests for the divisions and" << "\ntheir auxiliary offices as prompted:\n"; 74 for (int count = 0; count < N_DIVISIONS; count++) 75 { 76 double bud; 77 cout << "Division " << (count + 1) << ": "; 78 cin >> bud; 79 divisions[count].addBudget(bud); 80 cout << "Division " << (count + 1) << "'s auxiliary office:"; 81 cin >> bud; 82 auxOffices[count].addBudget(bud); 83 } 84 85 // Print the budgets 86 cout << setprecision (2); 87 cout << showpoint << fixed; 88 cout << "Here are the division budget requests:\n"; 89 for (int count = 0; count < N_DIVISIONS; count++) 90 { 91 cout << "\tDivision: " << (count + 1) << "\t\t\t$ "; 92 cout << setw(7); 93 cout << divisions[count].getDivBudget() << endl; 94 cout << "\tAuxiliary Office of Division " << (count+1); 95 cout << "\t$ "; 96 cout << auxOffices[count].getDivBudget() << endl; 97 } 98 99 // Print total requests 100 cout << "\tTotal Requests (including main office): $ "; 101 cout << Budget::getCorpBudget() << endl; 102 return 0; 103 }
注意,如前所述,可以使整个类成为另一个类的友元。Budget 类可以通过以下声明使 Aux 类成为友元:
friend class Aux;
但是,这可能并不是一个好主意,因为这将导致 Aux 的每个成员函数(包括稍后可能添加的函数)都可以访问 Budget 的私有成员。所以,最好的做法是只声明那些必须有权访问类的私有成员的函数作为友元。
参考:【1】https://www.runoob.com/cplusplus/cpp-this-pointer.html
【2】http://c.biancheng.net/view/2226.html
【3】http://c.biancheng.net/view/1489.html
侵权删。