原书p228
目录
定义成员函数
引入this
引入const成员函数
类作用域和成员函数
在类的外部定义成员函数
定义一个返回this对象的函数
首先要知道在书里面定义了一个这样的类:
struct Sales_data
{
std::string isbn() const{return bookNo;}
Sales_data& combine(const Sales_data&);
double avg_price() const;
//数据成员
std::string bookNo;
unsigned units_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&,Sales_data&);
定义成员函数
尽管所有成员函数都必须在类的内部声明,但是成员函数体可以定义在类内也可以定义在类外。对于Sales_data类来说,isbn函数定义在了类内,而combine和avg_price定义在了类外。
我们首先介绍isbn函数,它的参数列表为空,返回值是一个string对象。
注意:定义在类内部的函数是隐式的inline函数
关于这个函数isbn(),一个问题是他是如何获得bookNo成员所依赖的对象的呢?
引入this
让我们观察isbn成员函数的调用
Sales_data total; total.isbn();
p268页将介绍一种例外的形式
当我们调用成员函数时,实际上是在替某个对象调用它。如果isbn指向Sales_data的成员(这里是bookNo),则它隐式地指向调用该函数的对象的成员.
1.成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。例如,如果调用
total.isbn()
则编译器负责把total的地址传递给isbn的隐式形参this,可以等价地认为编译器将该调用重写成了如下的形式:
Sales_data::isbn(&total)
其中,调用isbn成员时传入了total的地址。
2.在成员函数内部,我们可以直接直接使用调用该函数的对象的成员,而无需通过成员访问运算符来做到这一点。任何对类成员的直接访问都被看作是this的隐式引用,也就是当isbn()使用bookNo时,相当于书写了this->bookNo一样
3.我们可以在成员函数内部使用this,尽管没有必要,但我们还是能把isbn定义成下面这种形式:
std::string isbn()const {return this->bookNo;}
this总是一个指向目前对象,所以this是一个常量指针
引入const成员函数
引入的必要性:
isbn函数的另一个关键之处是紧随参数列表之后的const关键字,这里,const的作用是修改隐式this只针的类型
默认情况下,在上面的例子中,this的类型是Sales_data*const。尽管this是隐式的,但它仍然需要遵循初始化规则,意味着我们不能把this绑定到一个常量对象上。
如果isbn是一个普通函数而且this是一个普通的指针参数,则我们应该把this声明成const Sales_data*const。毕竟,在isbn内不会改变this所指的对象,所以把this设置为指向常量的指针有助于提高函数的灵活性。
可以把isbn的函数体想象成如下形式:
std::string Sales_data::isbn(const Sales_data *const this)
{return this->bookNo;}
isbn可以读取调用它的对象的数据成员,但是不能写入新值。
Note:常量对象,常量对象的引用或指针都只能调用常量成员函数
类作用域和成员函数
类本身就是一个作用域,因此,isbn中用到的名字其实就是定义在Sales_data内的数据成员。
值得注意的是,bookNo定义在isbn之后,isbn还是能使用bookNo,因为编译器处理分为两步,首先编译成员的声明,然后才轮到成员函数体。因此,成员函数体可以随意使用类的其他成员而无需在意这些成员出现的次序。
在类的外部定义成员函数
返回类型,参数列表和函数名都得与类内部的声明保持一致。如果成员被声明成常量成员函数,那么定义的成员的名字必须包含它所属的类名:
double Sales_data::avg_price()const
{
if(units_sold)
return revenue/units_sold;
return 0;
}



