C++类的this指针详解
这篇文章主要讲解隐式this指针的概念,以及如何使用,包含const,基础部分不提太多
先直接给出一个C++Primer里的类,你可能还不能完全看懂,但是不着急,我们一点点解释
class Sales_data {
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
std::string bookNo;
unsigned untis_sold = 0;
double revenue = 0.0;
};
//Sales_data非成员函数接口
Sales_data add(const Sales_data, const Sales_data&);
std::ostream& print(std::ostream&, const Sales_data&);
std::istream& read(std::istream&, const Sales_data&);
类的所有成员都必须在类内部声明,但是成员函数体可以定义在外部,比如我们上面写的Sales_data类,isbn函数定义在了内部,combine和avg_price函数定义在了外部
定义在类内部的函数是隐式的inline函数
inline函数,即为调用时“内联地”展开的函数,也就是就说:调用时,并不通过函数调用的机制,而是通过将函数体直接插入调用处来实现的,比如以下调用
inline const string &
cout << shorter(s1, s2) << endl;
cout << {s1.size() < s2.size ? s1:s2} << endl;
”this“的概念
我们先看isbn函数
std::string isbn() const { return bookNo; }
它的参数列表为空,返回一个string对象,那它是怎么知道这个string对象是来自哪个类的?
this
先看一个调用的例子
total.isbn()
当我们调用成员函数时,实际上是在替某个对象(这里是total)调用它,isbn指向Sales_data的成员(bookNo),则它隐式地指向调用该函数的对象的成员
在total.isbn()调用中,isbn返回bookNo时,实际上它隐式地返回total.bookNo
成员函数isbn又通过一个名为this的额外的隐式参数来访问调用它的那个对象(this其实就是指向当前对象的指针),当我们调用一个成员函数时,用该函数的对象地址初始化this,this就会指向当前对象
例如调用total.isbn()则编译器负责把total的地址传递给isbn的隐式形参this,可以等价地理解为编译器将该调用重写成了以下形式
std::string isbn() const { return this->bookNo }
因为this的目的总是指向”这个“对象,所以this是一个常量指针(这是一个顶层const,this指针本身就是常量)
isbn() const
首先你要知道const的基本用法,顶层cosnt和底层const如何区别,建议先阅读这篇文章,下面这几行代码方便你回忆起顶层cosnt
int i = 0;
int* const p1 = &i; //p1本身是常量,顶层const
const int ci = 42; //ci本身是常量,顶层const
const int* p2 = &ci; //*在const之后,p2是指向常量的指针,底层const
const int* const p3 = p2; //先看左边是顶层,再看右边是底层,p3是指向常量的常量指针
const int& r = ci; //声明引用的const都是底层const,r是一个对常量的引用
好进入正题
先讲结论:"isbn() const里的const的作用是修改隐式this指针的类型
首先我们忘掉isbn,默认情况下,this的类型是指向类类型的 非常量版本的 常量指针(这是一个顶层const,this指针自己是常量,但是它所指向的对象并不是常量),在Sales_data的成员函数中,this的默认类型是Sales_data* const
尽管this是隐式的,但也遵循初始化规则,所以默认情况下我们不能把this直接绑定到一个常量对象上,同时也不能在一个常量对象上调用普通的函数成员(需要用到this)
具体来说,如果,我是说如果,如果isbn是一个普通函数没有const,this也是一个普通的指针,isbn内不会改变this所指的对象(只是返回bookNo),则我们应该把this声明成const Sales_data* const,所以把this设置为指向常量的指针可以提高灵活性
然而this隐式的,是不会出现在参数列表中的,所以在哪将this声明称指向常量的指针呢?C++的做法就是允许把const关键字放在成员函数的参数列表之后,就是我们看到的isbn() const,此时紧跟在参数列表后面的const表示this是一个指向常量的指针,像这样使用const的成员函数常被称作常量成员函数
//下面代码是非法的,只用于说明隐式的this指针如何使用,但我们不能显式定义this指针
//谨记此处的this是一个指向常量的指针,因为isbn是一个常量成员
std::string Sales_data::isbn(const Sales_data *const this){
return this->isbn;
}
定义一个返回this对象的函数
我们之前在Sales_data内声明了一个combine函数
Sales_data& combine(const Sales_data&);
现在我们在外部定义这个函数
Sales_data& Sales_data::combine(const Sales_data &rhs){
untis_sold += rhs.untis_sold;
revenue += rhs.revenue;
return *this;
}
Sales_data::combine使用作用域运算符以说明:我们定义了一个名为combine的函数,并且该函数声明在Sales_data类的作用域内,因此当combine使用untis_sold和revenue时,也是隐式地使用了Sales_data的成员
我们调用这个combine时
total.combine(trans)
total的地址被绑定到隐式的this参数上,而rhs绑定到了trans上
你应该注意到了,这个函数的关注点应该在于返回类型和返回语句
combine设计的初衷是尽量模仿+=运算符,+=把左侧的运算对象当成左值返回,为了尽可能一致,combine必须返回引用类型(这时左侧运算对象是一个Sales_data对象,所以返回类型为Sales_data&)
怎么返回呢,现在我们就不需要使用隐式的this指针访问函数调用者 的某个具体成员,而是需要把调用函数的对象当成一个整体来访问
return *this;
return语句解引用this指针,获得了执行该函数的对象,total.combine(trans)就会返回对total的引用
C++类的this指针详解的更多相关文章
- 【C++】智能指针详解(一):智能指针的引入
智能指针是C++中一种利用RAII机制(后面解释),通过对象来管理指针的一种方式. 在C++中,动态开辟的内存需要我们自己去维护,在出函数作用域或程序异常退出之前,我们必须手动释放掉它,否则的话就会引 ...
- c/c++指针详解(二)
指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占 ...
- [转]C++ 智能指针详解
转自:http://blog.csdn.net/xt_xiaotian/article/details/5714477 C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每 ...
- C++ 智能指针详解(转)
C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常 ...
- C++指针详解 (转)
C++指针详解 指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区, ...
- Delphi中TStringList类常用属性方法详解
TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 先把要讨论的几个属性列出来: 1.CommaText 2.Delim ...
- Python的Django框架中forms表单类的使用方法详解
用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...
- Java基础-DButils工具类(QueryRunner)详解
Java基础-DButils工具类(QueryRunner)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC ...
- c/c++指针详解(一)
一:相关概念 1.指针数组:int *p[6] 是数组,是一个存放指针的数组,也就是里面存放的是地址. 2.数组指针:int (*p)[6] ...
随机推荐
- SQL TRUNCATE TABLE 命令
SQL TRUNCATE TABLE 命令 SQL TRUNCATE TABLE 命令用于删除现有数据表中的所有数据. 你也可以使用 DROP TABLE 命令来删除整个数据表,不过 DROP TAB ...
- Nacos(一):Nacos介绍
前言 6月份阿里开源的Nacos出了1.0.1版本,从去年7月份第一个release版本到现在一直在默默关注 官方的版本规划为:Nacos从0.8.0开始支持生产可用,1.0版本可大规模生产可用,2. ...
- 为什么不建议在hbase中使用过多的列簇
我们知道,hbase表可以设置一个至多个列簇(column families),但是为什么说越少的列簇越好呢? 官网原文: HBase currently does not do well with ...
- Redis----NoSql数据库笔记
介绍:Redis 是一个开源的使用 ANSI C 语言编写.遵守 BSD 协议.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的 API的非关系型数据库. 传统数据 ...
- IntelliJ IDEA 2019 快捷键终极大全,速度收藏!
转载注明:https://blog.csdn.net/WantFlyDaCheng/article/details/100078777 自动代码 查询快捷键 其他快捷键 调试快捷键 重构 十大Inte ...
- CocosBuilder 学习笔记(2) .ccbi 文件结构分析
ccbi总体结构 CCBReader按字节读取.ccbi内容,每个字节8位二进制. .ccbi总体结构分为4个部分: Header 第0-3字节:ibcc .ccbi文件的标志.readHeader方 ...
- Leetcode之深度优先搜索(DFS)专题-200. 岛屿数量(Number of Islands)
Leetcode之深度优先搜索(DFS)专题-200. 岛屿数量(Number of Islands) 深度优先搜索的解题详细介绍,点击 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计 ...
- Jenkins教程(三)添加凭据与流水线拉取Git代码
前言 本文旨在配置凭据.使用Git仓库中的Jenkinsfile与使用声明式流水线拉取Git代码 使用SVN等其他版本控制工具,请参考使用Pipeline-Syntax生成对应代码块 凭据(crede ...
- 洛谷 P1514 【引水入城】
题库 :洛谷 题号 :1514 题目 :引水入城 link :https://www.luogu.org/problemnew/show/P1514 思路 :搜索从第一排开始能覆盖最后一排的区间L ~ ...
- 爬虫工程师分享:三步就搞定 Android 逆向
本文源于我近期的一次公司内部分享,通过逆向某款 APP 来介绍逆向过程.由于仅作为学习用途,APP 的相关信息会被遮盖,敬请理解. 关于逆向 逆向--包括但不限于通过反编译.Hook 等手段,来解析一 ...