《Effective C++》条款24:若所有参数皆需要类型转换,请采用non-member函数

本章节主要讨论参数转换的问题,炸出来很多之前没怎么看到的点;

 

对于书上之前,举了这样一个返回const by-value的例子;

#include<iostream>
#include<vector>
using namespace std;


class rational {
public:
	rational(int nn = 0, int dd = 1) :n(nn), d(dd) {};
	int rn() const {
		return n;
	}
	int rd() const {
		return d;
	}
	const rational operator* (const rational& rhs) const {
		return rational(n * rhs.rn(), d * rhs.rd());
	}
private:
	int n;
	int d;
};

int main() {
	rational oneEight(1, 8);
	rational oneHalf(1, 2);
	rational result = oneHalf * oneEight;
	result = result * oneEight;
	system("pause");
	return 0;
}

这里注意一下const对象的问题:

如果返回const对象,则只能调用const函数,来保障自己的不变性;

这里return const rational,返回的是一个新的对象,并没有改变this的值;

 

看到这里当时有一个疑惑,返回的是const对象,为什么可以赋值给result?

本质上是因为返回值和接受值是两个过程,这里有一篇神博客讲的非常详细https://www.oschina.net/question/2412650_2184000

所以尽管返回值是const的,但是左值接受只会接受非const部分,并不会接受const修饰符;

 

但是如果采用该种类型,会造成隐式转换失败的问题:

rational oneEight(1, 8);
rational oneHalf(1, 2);
rational result = oneHalf * 2;
result = 2 * oneEight;

考虑如上,会发现最后一条2*oneEight报错:无法进行类型转换; 

本质原因:整数2没有相应的class来进行operator*的类型转换,而oneHalf*2中的2进行了类型转换;

 

直白的说就是发生了下列转换:

const rational temp(2);

result=oneHalf*temp;

 

但是值得注意的是,如果是explictic声明构造函数,会导致隐式复制转换失败,所以如果想采用这种形式必须要保证是non-explictic的;

 

注意这里的const rational temp(2),这里2是作为参数初始化列表的第一个参数,其他的值作为缺省参数填入;

所以相当于const rational temp(2,1);

 

如果想让两种隐式转换都成功,不妨采用non-member函数,来进行符号计算:

class rational {
public:
	rational(int nn = 0, int dd = 1) :n(nn), d(dd) {};
	int rn() const {
		return n;
	}
	int rd() const {
		return d;
	}
private:
	int n;
	int d;
};

const rational operator* (const rational& lhs, const rational& rhs) {
	return rational(lhs.rn()*rhs.rn(),lhs.rd()*rhs.rd());
}

 

并且需要注意的是,一般不能做member函数,就也别做friend函数了;

 

posted @ 2020-12-09 16:27  暮云林凌  阅读(122)  评论(0)    收藏  举报