这篇文章主要讲解隐式 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 的引用
来源: https://www.cnblogs.com/zhxmdefj/p/11572570.html