读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数
2013-06-16 16:58
471 查看
还是举书上的有理数例子:
有理数的私有成员是分子numerator和分母denominator,定义了构造函数,注意这个构造函数前面没有加explicit关键字,这意味着允许隐式转换(即标题所说的类型转换)。GetNumerator()和GetDenominator()是用来获取私有成员的值的,下面是我们要重点讲述的乘法运算符的重载。
我们的问题是,用什么方式实现乘法运算符的重载呢?我记得在我初学C++时,书上介绍了两种方法,一种是采用类内成员函数(也就是上面这段程序的写法),另一种是采用友元函数,像这样:
就这两种方法而言,其实友元函数的实现方式更优,为什么这样说?因为它们对封装性的冲击是相当的,但友元函数支持下面的代码:
成员函数实现却在r2 = 2 * r1上通不过编译。将这句话还原成运算符函数的形式,就能看到原因了:
哈哈,这样就知道为什么编译器不允许了,2必须首先转成Rational对象,才能使用它自身的operator*,但编译器不允许类型转换成this(隐含的自身指针)的,所以报错。
但对于友元函数实现,我们也将之还原成运算符函数的形式:
第一个参数会发生隐式转换(因为构造函数前面没有explicit),不会同时进行向this的转换,所以编译器是放行的。
这里插一句,隐式转换的发生过程就像这样:
综上,成员函数实现不能支持含隐式转换的交换率,而友元函数实现却可以,故我们认为友元函数实现要优于成员函数实现(程序不支持乘法交换率是难以接受的)。
解决了这个问题之后,再来思考一下,能否对封装性进行改进,因为条款二十三说了,宁以non-member,non-friend函数去替换member函数,其实对友元函数形式稍加修改,去掉friend,改用public成员变量来访问函数内的私有成员,就可以实现好的封装,像这样:
在这个函数里面,是不能直接访问到类的私有成员的,因而保证了好的封装性。
最后总结一下:
如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member,且为了封装,最好是个non-friend。
class Rational { private: int numerator; int denominator; public: Rational(int n = 0, int d = 1): numerator(n), denominator(d){assert(denominator != 0);} int GetNumerator() const{return numerator;} int GetDenominator() const {return denominator;} const Rational operator* (const Rational& r) { return Rational(numerator * r.numerator, denominator * r.denominator); } };
有理数的私有成员是分子numerator和分母denominator,定义了构造函数,注意这个构造函数前面没有加explicit关键字,这意味着允许隐式转换(即标题所说的类型转换)。GetNumerator()和GetDenominator()是用来获取私有成员的值的,下面是我们要重点讲述的乘法运算符的重载。
我们的问题是,用什么方式实现乘法运算符的重载呢?我记得在我初学C++时,书上介绍了两种方法,一种是采用类内成员函数(也就是上面这段程序的写法),另一种是采用友元函数,像这样:
class Rational { private: int numerator; int denominator; public: Rational(int n = 0, int d = 1): numerator(n), denominator(d){assert(denominator != 0);} int GetNumerator() const{return numerator;} int GetDenominator() const {return denominator;} friend const Rational operator* (const Rational& r1, const Rational& r2); }; const Rational operator* (const Rational& r1, const Rational& r2) { return Rational(r1.numerator * r2.numerator, r1.denominator * r2.denominator); }
就这两种方法而言,其实友元函数的实现方式更优,为什么这样说?因为它们对封装性的冲击是相当的,但友元函数支持下面的代码:
int main() { Rational r1(3, 5); Rational r2(2, 1); r2 = r1 * 2; r2 = 2 * r1; return 0; }
成员函数实现却在r2 = 2 * r1上通不过编译。将这句话还原成运算符函数的形式,就能看到原因了:
r2 = 2.opeator* (r1);
哈哈,这样就知道为什么编译器不允许了,2必须首先转成Rational对象,才能使用它自身的operator*,但编译器不允许类型转换成this(隐含的自身指针)的,所以报错。
但对于友元函数实现,我们也将之还原成运算符函数的形式:
r2 = operator *(2, r1);
第一个参数会发生隐式转换(因为构造函数前面没有explicit),不会同时进行向this的转换,所以编译器是放行的。
这里插一句,隐式转换的发生过程就像这样:
const Rational temp(2); r2 = operator*(temp, r1);
综上,成员函数实现不能支持含隐式转换的交换率,而友元函数实现却可以,故我们认为友元函数实现要优于成员函数实现(程序不支持乘法交换率是难以接受的)。
解决了这个问题之后,再来思考一下,能否对封装性进行改进,因为条款二十三说了,宁以non-member,non-friend函数去替换member函数,其实对友元函数形式稍加修改,去掉friend,改用public成员变量来访问函数内的私有成员,就可以实现好的封装,像这样:
const Rational operator* (const Rational& r1, const Rational& r2) { return Rational(r1.GetNumerator() * r2.GetNumerator(), r1.GetDenominator() * r2.GetDenominator()); }
在这个函数里面,是不能直接访问到类的私有成员的,因而保证了好的封装性。
最后总结一下:
如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member,且为了封装,最好是个non-friend。
相关文章推荐
- 读书笔记《Effective c++》 条款24 若所有参数皆需要类型转换,请为此采用non-member函数
- Effective C++ Item 24 若所有参数皆需类型转换,请为此采用non-member函数
- 条款24:如果所有的参数都需要类型转换,那么请为此采用non-member函数
- Effective C++——》条款24:若所有参数皆需类型转化,请谓词函数采用non-member函数
- 条款24 若所有参数皆需类型转换,请为此采用non-member函数
- 条款24:若所有参数皆需要类型转换,请为此采用non-member函数(Declare non-member functions when type conversions should apply to all parameters)
- Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数
- Effective C++ 条款24 若所有参数皆需类型转换,请为此采用non-member函数
- 条款24:若所有参数皆需类型转换,请为此采用non-member函数
- 条款24:若所有参数皆需类型转换,请为此采用non-member函数
- 条款24:若所有参数都需要类型转换,请为此采用non-member函数
- Effective C++ -----条款24:若所有参数皆需类型转换,请为此采用non-member函数
- 《Effective C++》学习笔记条款24 若所有参数皆需类型转换,请为此采用non-member函数
- 《Effect C++》学习------条款24 :若所有参数皆须类型转换,请为此采用non-member函数
- 条款24:若所有参数皆需类型转换,请为此采用non-member函数
- 条款24 若所有参数皆需类型转换,请为此采用non-member函数
- effective C++ 条款 24:若所有参数皆需类型转换,请为此采用non-member函数
- 若所有参数需类型转换,采用non-member函数(Effective_C++(24))
- Effective C++学习之-------若所有参数皆需类型转换,请为此采用non-member函数
- 条款24::若所有参数皆需类型转换,请为此采用 non-member 函数