zoukankan      html  css  js  c++  java
  • 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++ 内置宏定义 与 预编译指令
    C++ 反射机制的简单实现
    Intellij打包jar文件,“java.lang.SecurityException: Invalid signature file digest for Manifest main attrib
    IntelliJ IDEA 运行你的第一个Java应用程序 idea运行main方法
    IDEA重新打jar包时报错MANIFEST.MF already exists in VFS
    在 RPA10.X 运行异常,RPA9 却正常的问题处理
    Python判断文件是否存在的三种方法
    Python日期时间函数
    Chrome提示:"请停用以开发者模式运行的扩展程序"的解决办法
    Win10提示“无法打开此计算机上的组策略对象”如何解决
  • 原文地址:https://www.cnblogs.com/zhxmdefj/p/11572570.html
Copyright © 2011-2022 走看看