C++ 类:成员函数,this,const成员函数,类作用域,类外部定义成员函数,定义返回 this 对象的函数 (return *this? 解决)

定义 Sales_data 类

struct Sales_data {
    std::string isbn() const { return bookNo; }		// 返回 isbn 编号
    Sales_data& combine (const Sales_data&);
    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&);

定义在类内部的函数是隐式的 inline 函数

Sales_data 类的说明
  • 一个 isbn 成员函数,用于返回某书的 ISBN 编号
  • 一个 combine 成员函数, 实现销量与收入 += 操作
  • 一个 add 函数,实现销量与收入 + 操作
  • 一个 read 函数,实现直接读入 Sales_data 类,即将数据从 istream 读取到 Sales_data 中
  • 一个 print 函数,实现直接输出 Sales_data 类,即将数据从 Sales_data 输出到 ostream 中

引入this

假设有代码:

	Sales_data tmp;
	cout << tmp.isbn() << endl;

我们知道,isbn 函数是 return bookNo,那么编译器是如何返回的 tmp.bookNo 呢?

可以以下伪代码来理解,用于说明成员函数的实际执行过程

	Sales_data::isbn(&tmp);

其实是调用 isbn 函数时传入了 tmp 的地址。

可知:在成员函数内部,我们可以直接使用调用该函数的对象的成员,不需要通过 成员访问运算符来做到这一点,因为 this,对类成员的直接访问都被看做 this 的隐式引用。

换句话说,isbn() 函数可以这样写:

	std::string isbn() const { return this.bookNo; }

this 指针是一个常量指针,不允许修改 this 中保存的地址。

引入 const 成员函数

在 Sales_data 类的代码中,可以看到 isbn() 函数后面有一个 const 关键字,这里的 const 的作用是修改隐式 this 指针的类型。

默认情况下,this 的类型是指向类类型非常量版本的常量指针。如在本类中,this 的类型是 Sales_data *const,但是仍需要遵守初始化规则,即不能把 this 绑定到一个常量对象上。

换句话说,假设我们去掉了 isbn() 函数后面的 const 关键字,现在有 const Sales_data x;

是无法调用 x.isbn() 函数的,因为 x 是 const 对象,this (默认的)隐式的指向的是 非 const 对象,发生了错误。

解决这种问题,C ++ 的做法是把 const 关键字放在成员函数的参数列表之后,隐式的表示 this 是一个指向常量的指针 (即此时 this 的指针类型为 const Sales_data* const) ,这样的成员函数叫做常量成员函数

!!注意:是隐式的表示,所以不能显式的定义一个 this 指针,即以下代码是错误的

	std::string isbn(const Sales_data* const this) {
        return this -> isbn;
    }

常量对象,以及常量对象的引用或指针都只能调用常量成员函数

类的作用域与成员函数

再次回顾以上 Sales_data 类的定义代码,可以发现 isbn() 函数中用到了 bookNo 成员变量,然后 bookNo 的定义却是在 isbn() 函数定义之后,但是并没有发生编译错误。

原因: 编译器分两步处理类:首先编译成员的声明,然后才轮到成员函数体 (如果有的话)。因此成员函数他可以随意使用类中的其他成员而无须在意成员的出现次序。

在类的外部定义成员函数

首先肯定是和类内部的声明在返回类型、参数列表、函数名,以及是否被声明为常量成员函数 一致。然后需要用 作用域运算符指明所属的类。如以下代码:

double Sales_data::avg_price() const {
    if(units_sold)
    	return revenue / units_sold;
    return 0;
}

指明所属的类后,编译器才能理解剩余代码是位于类作用域内的。所以呢,revenue 与 units_sold 都是隐式的使用了 Sales_data 的成员

定义一个返回 this 对象的函数

函数 combine 是类似于实现 += 操作的函数,调用该函数的对象代表 += 的左侧对象,传入实参代表 += 的右侧对象。

Sales_data& Sales_data::combine(const Sales_data &rhs) {
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;						// 返回调用该函数的对象
}

关于这个函数,有几点不懂。暂记:为什么有返回类型,而且是 Sales_data&?为什么函数返回类型不是 void,然后不执行 return?为什么用 void 的写法也可以编译通过并运行?

C++ primer是这样写道的 (我还是不懂):一般来说,当定义的函数类似于某个内置运算符时,应该令该函数的行为尽量模仿这个运算符。内置的 += 运算把左侧对象当成左值返回,为了保持一致, combine 函数必须返回引用类型。此时的左侧对象是 Sales_data 对象,所以返回类型应该是 Sales_data&。然后 return 语句解引用 this 指针以获得执行该函数的对象。

-----------2月9日更新-----------

对于以上删除线提出的问题。首先回答后面的:函数当然可以用 void 然后不执行 return 语句,并不影响对于一次的使用。(!注意:是一次的使用)。

为什么是一次的使用?
 上面有写道,当定义的函数类似于某个内置运算符时,应该令该函数的行为尽量模仿这个运算符。也就是说, combine 函数是模仿的 += 操作,所以应该尽量和 += 的操作相似。
 += 具有右结合律,这一点很重要。
 假设有代码:

	int a = 1,b = 2,c = 3;
	a += b += c;

其中,a += b += c 语句是可以执行的。假设上面的 combine 函数不是模仿 += ,而是重载 += 运算符,如果没有 return *this; 那么 += 最多执行一次。

即最多有: a += b; 或者 b += c;
没有 a += b += c; 语句。当执行完 b += c 之后,a += b 就无法执行了。因为没有返回 该对象 以继续向左执行。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值