mooc西工大魏英老师的课程通道关闭了,难受。现在边看工程代码边重温刷第一遍C++时候的知识点,顺序没有按照大纲的来,想到哪写到哪。

this是干啥用的?

简介:在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象(意味着可以访问当前对象的所有成员)。

实质:this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。
this 作为隐式形参,本质上是成员函数的局部变量,所以只能用在成员函数的内部,并且只有在通过对象调用成员函数时才给 this 赋值。
在《C++函数编译原理和成员函数的实现》一节中讲到,成员函数最终被编译成与对象无关的普通函数,除了成员变量,会丢失所有信息,所以编译时要在成员函数中添加一个额外的参数,把当前对象的首地址传入,以此来关联成员函数和成员变量。这个额外的参数,实际上就是 this,它是成员函数和成员变量关联的桥梁。

注意:友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

(问题来了,什么是友元?详见文末)

 #include <iostream>
using namespace std; class Student{
public:
void setname(char *name);
void setage(int age);
void setscore(float score);
void show();
private:
char *name;
int age;
float score;
}; void Student::setname(char *name){
this->name = name;
}
void Student::setage(int age){
this->age = age;
}
void Student::setscore(float score){
this->score = score;
}
void Student::show(){
cout<<this->name<<"的年龄是"<<this->age<<",成绩是"<<this->score<<endl;
} int main(){
Student *pstu = new Student;
pstu -> setname("李华");
pstu -> setage();
pstu -> setscore(96.5);
pstu -> show(); return ;
}

运行结果是:

 李华的年龄是16,成绩是96.

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 的值,如下所示:

 void Student::printThis(){
cout<<this<<endl;
}
//然后在 main() 函数中创建对象并调用 printThis():
Student *pstu1 = new Student;
pstu1 -> printThis();
cout<<pstu1<<endl; Student *pstu2 = new Student;
pstu2 -> printThis();
cout<<pstu2<<endl;

运行结果:

 0x7b17d8
0x7b17d8
0x7b17f0
0x7b17f0

可以发现,this 确实指向了当前对象,而且对于不同的对象,this 的值也不一样。

几点注意:

  • this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。
  • this 只能在成员函数内部使用,用在其他地方没有意义,也是非法的。
  • 只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用(后续会讲到 static 成员)。

什么是友元?

私有成员对于类外部的所有程序部分而言都是隐藏的,访问它们需要调用一个公共成员函数,但有时也可能会需要创建该规则的一项例外。

友元函数是一个不属于类成员的函数,但它可以访问该类的私有成员。换句话说,友元函数被视为好像是该类的一个成员。友元函数可以是常规的独立函数,也可以是其他类的成员。实际上,整个类都可以声明为另一个类的友元。

为了使一个函数或类成为另一个类的友元,必须由授予它访问权限的类来声明。类保留了它们的朋友的 "名单",只有名字出现在列表中的外部函数或类才被授予访问权限。通过将关键字 friend 放置在函数的原型之前,即可将函数声明为友元。

在 Budget 类的以下声明中,另一个类的 addBudget 函数 Aux 已声明为友元:

 class Budget
{
private:
static double corpBudget;
double divBudget;
public:
Budget() { divBudget = ; }
void addBudget(double b)
{
divBudget += b;
corpBudget += divBudget;
}
double getDivBudget() const { return divBudget; }
static double getCorpBudget() { return corpBudget; }
static void mainOffice(double);
friend void Aux::addBudget (double) ; // 友元
};

假设另一个 Aux 类代表一个分部的附属办公室,也许在另一个国家。附属办公室提出了一个单独的预算要求,该要求必须添加到整个企业的预算中。则 Aux::addBudget 函数的友元声明告诉编译器,该函数己授予访问 Budget 的私有成员的权限。该函数釆用 double 类型的实参,表示要添加到企业预算中的金额:

 class Aux
{
private:
double auxBudget;
public:
Aux() { auxBudget =; }
void addBudget(double);
double getDivBudget() { return auxBudget; }
};

以下是 Aux addBudget 成员函数的定义:

 void Aux::addBudget(double b)
{
auxBudget += b;
Budget::corpBudget += auxBudget;
}

形参 b 被添加到企业预算中,这是通过使用表达式 Budget::corpBudget 来访问并实现的。下面的程序演示了这些类在完整程序中的用法。

 //auxil.h的内容
#ifndef AUXIL_H
#define AUXIL_H
// Aux class declaration.
class Aux
{
private:
double auxBudget;
public:
Aux() { auxBudget = ; }
void addBudget(double);
double getDivBudget() const { return auxBudget; }
};
#endif
//budget3.h的内容
#ifndef BUDGET3_H
#define BUDGET3_H
#include "auxil.h" // For Aux class declaration
//Budget class declaration.
class Budget {
private:
static double corpBudget;
double divBudget;
public:
Budget() { divBudget =; }
void addBudget(double b)
{
divBudget += b;
corpBudget += divBudget;
}
double getDivBudget() const {return divBudget;}
static double getCorpBudget() {return corpBudget;}
static void mainOffice(double);
friend void Aux::addBudget(double);
};
#endif //budget3.cpp的内容
#include "budget3.h"
//Definition of static member.
double Budget::corpBudget = ;
void Budget:imainOffice(double budReq)
{
corpBudget += budReq;
} //auxil.cpp的内容
#include "auxil.h"
#include "budget3.h"
void Aux::addBudget(double b)
{
auxBudget += b;
Budget::corpBudget += auxBudget;
} //main程序的内容
//This program demonstrates a static class member variable. #include <iostream>
#include <iomanip>
#include "budget3.h"
using namespace std; int main()
{
const int N_DIVISIONS = ;
// Get the budget requests for the divisions and offices
cout << "Enter the main office's budget request:";
double amount;
cin >> amount;
Budget:imainOffice(amount);
// Create the division and auxiliary offices
Budget divisions [N_DIVISIONS];
Aux auxOffices[N_DIVISIONS];
cout << "\nEnter the budget requests for the divisions and" << "\ntheir auxiliary offices as prompted:\n";
for (int count = ; count < N_DIVISIONS; count++)
{
double bud;
cout << "Division " << (count + ) << ": ";
cin >> bud;
divisions[count].addBudget(bud);
cout << "Division " << (count + ) << "'s auxiliary office:";
cin >> bud;
auxOffices[count].addBudget(bud);
} // Print the budgets
cout << setprecision ();
cout << showpoint << fixed;
cout << "Here are the division budget requests:\n";
for (int count = ; count < N_DIVISIONS; count++)
{
cout << "\tDivision: " << (count + ) << "\t\t\t$ ";
cout << setw();
cout << divisions[count].getDivBudget() << endl;
cout << "\tAuxiliary Office of Division " << (count+);
cout << "\t$ ";
cout << auxOffices[count].getDivBudget() << endl;
} // Print total requests
cout << "\tTotal Requests (including main office): $ ";
cout << Budget::getCorpBudget() << endl;
return ;
}

注意,如前所述,可以使整个类成为另一个类的友元。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

侵权删。

C++编程学习(九)this指针&友元函数的更多相关文章

  1. 计算机专业C语言编程学习重点:指针化难为易

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  2. IOS学习之路-- 指针&宏函数

    如果*p被()包住,说明指针变量p将来指向的是函数 //声明一个指针变量 //int (*p)(int, int) = sum; int (*p)(int, int); p = sum; // 如果* ...

  3. Windows核心编程学习九:利用内核对象进行线程同步

    注:源码为学习<Windows核心编程>的一些尝试,非原创.若能有助于一二访客,幸甚. 1.程序框架 #include "Queue.h" #include <t ...

  4. Linux网络编程学习(九) ----- 消息队列(第四章)

    1.System V IPC System V中引入的几种新的进程间通信方式,消息队列,信号量和共享内存,统称为System V IPC,其具体实例在内核中是以对象的形式出现的,称为IPC 对象,每个 ...

  5. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  6. Javascript高级编程学习笔记(23)—— 函数表达式(1)递归

    前面的文章中,我在介绍JS中引用类型的时候提过,JS中函数有两种定义方式 第一种是声明函数,即使用function关键字来声明 第二种就是使用函数表达式,将函数以表达式的形式赋值给一个变量,这个变量就 ...

  7. Javascript高级编程学习笔记(7)—— 函数

    前几天有事耽搁了,今天继续更新 今天的主要内容是JS中的函数 这一篇主要讲函数的定义等内容,至于变量提升.执行环境.闭包.内存回收等内容在后面讲,高玩们可以不用看下面的正文了. 函数 首先来讲,函数对 ...

  8. Javascript高级编程学习笔记(26)—— 函数表达式(4)私有变量

    私有变量 严格来讲,JS中没有私有成员的概念,所有对象属性都是公有的. 但是JS中有私有变量的概念 所有在函数中定义的变量都可以认为是私有变量,因为不能在函数外部进行访问 私有变量包括 1.函数参数 ...

  9. Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包

    昨天的文章中主要记录了,函数表达式与函数声明的区别 以及在JS中如何安全地使用递归 那么既然要深入地理解JS中的函数,闭包就是一个绕不开的概念 闭包 JS高编一书中对闭包的概念定义如下: 闭包是指有权 ...

随机推荐

  1. px(像素)、pt(点)、ppi、dpi、dp、sp之间的关系

    px:pixel,像素,电子屏幕上组成一幅图画或照片的最基本单元 pt:point,点,印刷行业常用单位,等于1/72英寸 ppi:pixel per inch,每英寸像素数,该值越高,则屏幕越细腻 ...

  2. Session 'app': Error Installing APKs app 在手机或虚拟机上调试报错

    解决方案: build --clean project

  3. 通过Java创建XML(中文乱码已解决)

    package com.zyb.xml; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.Ou ...

  4. B树 VS B+树

    参考:https://www.cnblogs.com/vincently/p/4526560.html

  5. 蓝桥杯java 迷宫

    0101010100101100100101011001011010010000100010101000001000100000101010010000100000001001100110100101 ...

  6. ubuntu18.04 复制或剪切某文件夹下的前x个文件到另一个文件夹下

    该代码可以将file_path_src文件夹中的前cnt个文件,剪切或复制到file_path_tar文件夹下,前提是file_path_src中的文件名可以排序.如VOC数据集提取某个类的图片和xm ...

  7. 课堂测试用javaweb写一个注册界面,并将数据保存到后台数据库(部分完成)

    今天我到现在为止,也只完成了数据库的连接,还没有写前台的javascript的检查输入的代码,打算周四前完成. 代码如下: package Dao; import java.sql.Connectio ...

  8. json序列化(重要)

    (1)同(2)public JsonResult JsonUserGet() { DataSet ds = Web_User.P_LG_User_Get(nUserId); return Json(J ...

  9. windows10更换mysql8.0.17

    下载windows版本mysql 解压后创建my.ini文件初始化mysql和data文件夹用来存数据 my.ini内容 [mysqld] # 设置3306端口 port=3306 # 设置mysql ...

  10. Myeclipse 安装时候android adt, android sdk常见问题

    离线版adt安装  可以随意百度adt下载 安装时候注意断网模式,否则会连接到服务器耗费很长时间:如果安装报错,可能是adt与Myeclipse版本不匹配,如我用的是Myeclipse8.6,安装AD ...