《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函数了;

浙公网安备 33010602011771号