类 this指针 const成员函数
C++ Primer 第07章 类
Sales_data类的定义如下:
1 #ifndef SALES_DATA_H 2 #define SALES_DATA_H 3 #include <string> 4 #include <iostream> 5 class Sales_data { 6 public: 7 std::string isbn() const {return bookNo;} 8 Sales_data& combine(const Sales_data&); 9 double avg_price() const; 10 private: 11 std :: string bookNo ; 12 unsigned units_sold = 0; 13 double revenue = 0.0; 14 }; 15 Sales_data add(const Sales_data&, const Sales_data&); 16 std::ostream &print(std::ostream&, const Sales_data&); 17 std::istream &read(std::istream&, const Sales_data&); 18 #endif
注意第8行:
std::string isbn() const {return bookNo;}
这里const的作用是修改隐式this指针的类型,默认情况下,this的类型是指向类类型非常量版本的常量指针。例如在Sales_data成员函数中,this的类型是Sales_data *const,即类一旦实例化一个对象后,this指向这个对象,是不能改变的,但是对象本身可以变(通俗的讲,this保存的地址不能变,但是*this指向的内容是可以变的,所以*this是非常量,不可以将this绑定一个常量对象),举个例子:
const int a = 5; //a为整型常量 int *const pa = &a; //pa是常量指针,但是*pa可以变,但是a又是常量,所以报错
所以这样就会带来一个问题:我们不能在一个常量对象上调用普通成员函数,测试如下:
去掉const,测试代码如下:
#include "Sales_data.h" int main() { Sales_data data1; std::cout << data1.isbn() << std::endl; return 0; }
结果OK,data1是非常量,调用普通成员函数没有问题,下面做一个改变,将data1声明成常量
#include "Sales_data.h" int main() { const Sales_data data1; std::cout << data1.isbn() << std::endl; return 0; }
CodeBlocks编译报错
error: passing 'const Sales_data' as 'this' argument of'std::string Sales_data::isbn()' discards qualifiers [-fpermissive]
如果isbn是一个普通函数而this是一个普通指针参数,则我们应该把this声明成const Sales_data *const。毕竟,在isbn的函数体内不会改变this所指向的对象,所以把this设置为指向常量的指针有助于提高函数的灵活性。
然而,this是隐式的并且不会出现在参数列表中,所以在哪儿将this声明成指向常量的指针就成为我们必须面对的问题。C++语言的做法是允许把const关键字放在成员函数的参数列表之后,此时,紧跟在参数列表后面的const表示this是一个指向常量的指针。像这样使用const的成员函数被称作常量成员函数(const member function)。
可以把isbn的函数体想象成如下形式:
//伪代码,说明隐式的this指针是如何使用的 //下面的代码是非法的:因为我们不能显示地定义自己的this指针 //谨记此处的this是一个指向常量的指针,因为isbn是一个常量成员 std::string Sales_data::isbn(const Sales_data *const this) { return this->isbn; }
因为this是指向常量的指针,所以常量成员函数不能改变调用它的对象的内容。在上例中,isbn可以读取调用它的对象的数据成员,但是不能写入新值。
note: 常量对象,以及常量对象的引用或指针都只能调用常量成员函数。