若所有的参数皆需要类型转换——请为此采用non-member函数#

经常使用C++的程序猿(希望更多的程序媛),一般不会同意让classes支持类型转换,至于为什么,请看后续的博客。假如我们设计一个表示有理数的class,允许”整数隐式转换为有理数似乎很合理“。首先来一个简单的实现。

class Rational
{
public:
Rational(int numerator = 0,int denominator = 1; //允许int-to-Rational隐式转换
int numerator()const;
int denominator()const;
const Rational operator*(const Rational& rhs)const; //有理数的乘法
...
};

有理数,我们很自然地为他实现了乘法的运算。我们可以轻松地实现两个有理数相乘,但是,假如我们想要进行混合运算呢?在下面的例子中,2在第一个参数与第二个参数的位置进行隐私类型转换。


Rational half(1,2);
half = half * 2; //1. 通过编译
half = 2 *half; //2. 无法通过编译

为什么会这样呢?对于1,编译器解释如下,所以很正常地通过了编译。

operator*(Rational& this,Rational& rhs);    //函数的定义部分
//第一个参数是没办法改变的,一定是被乘数
half.operator(Rational(2)); //函数的调用部分,2被隐式转换为了有理数
//与下面的代码一致
const Rational temp(2);
result = half * temp;

编译器拿到2的时候,知道operator*()需要一个Rational,也知道只要调用Rational的构造函数就能够变出一个适当的Rational,所以,它就做了。

结果就是上面的例子。当然,必须存在non-explicit编译器才会这么做。

而对于2中的代码呢,编译器首先试着如下解释

2.operator*(half);

很明显,2.operator()是不存在的东西,所以,编译器会尝试着寻找一个non-memb operator(),但结果是:没有找到。所以只能返回一个错误。

很明显,上面对于同一个操作符,却有了两种截然不同的结果,你十分抵触。然后你就会义愤填膺地把构造函数修改为explicit。结果是:两者一致了,都不支持混合运算。但是,我们的目标不仅仅在于一致性,我们还希望它支持混合运算。那么,请拿出我们的利器:non-member函数。我们暂时允许编译器执行隐式类型转换。

class Rational
{
...
};
const Rational operator*(const Rational& lhs,const Rational& rhs);
Rational half(1,2);
half = half * 2; //通过编译
half = 2 * half; //通过编译

真的是峰回路转疑无路,千辛万苦终于找到可行之道。对于上面的代码,编译器会对每个2都转换为Rational(2)。当你完成了一天的工作后,最后一个要操心的问题是:是否需要一个non-member friend函数?假如否定的,member的对立面不是non-member friend函数。使用了friend,意味着公开自己的所有隐私。这种严重破坏自身隐私的可不是好事,可以参考以下的博客太过亲密往往不好——用NON-MEMBER,NON-FRIEND替换MEMBER函数还有为了更好更方便地活着——爱上PRIVATE.

总结一下

  1. 假如你需要为某个函数的所有参数都进行类型转化的时候,这个函数必须是non-member。

  2. member的对立面不是non-member friend,请慎用friend。

若所有的参数皆需要类型转换——请为此采用non-member函数的更多相关文章

  1. Effective C++ -----条款24:若所有参数皆需类型转换,请为此采用non-member函数

    如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member.

  2. 条款24:若所有参数皆需要类型转换,请为此采用non-member函数(Declare non-member functions when type conversions should apply to all parameters)

    NOTE: 1.如果你需要为某个函数的所有参数(包括this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member.

  3. [Effective C++ --024]若所有参数皆需类型转换,请为此采用non-member函数

    引言 假设我们有这样的类: class A{ public: A(, ) {}; int num() const; int den() const; const A operator* (const ...

  4. [EffectiveC++]item24:若所有参数皆需类型转换,请为此采用non-member函数

    Declare non-member functions when type conversions should apply to all parameters. 104页 只有当参数被列于参数列( ...

  5. 【24】若所有参数皆需类型转换,请为此采用non-members函数

    1.令class支持隐式类型转换,往往是个糟糕的主意.但有些情况是合理的,比如数值类型.考虑,有理数Rational有分子,分母两个字段,缺省参数值为0,1.Ration a = 2;我们期望构造一个 ...

  6. 读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数

    class A { private: int a; public: A(int x) :a(x){} A operator*(const A& x) { return A(a*x.a); } ...

  7. 条款24:如果所有的参数都需要类型转换,那么请为此采用non-member函数

    首先还是下面这个class; class Rational{ public: Rational(, ); int numurator() const; int denominator() const; ...

  8. 微信h5支付出现“商家参数格式有误,请联系商家解决”

    在浏览器进行微信h5支付时出现:

  9. js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快、简单 post:安全,量大,不缓存)(服务器同步和异步区别:同步:等待服务器响应当中浏览器不能做别的事情)(ajax和jquery一起用的)

    js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快.简单 post:安全,量大,不缓存)( ...

随机推荐

  1. 小K(wifi)插座剖解

    1.主控 AR9331 400MHZ MIPS 24k内核 2.flash:w9425G6JH-5 1352P 6316CF500ZY  RAM 32M

  2. E: could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporary unavailable) E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is an other process using it

    1. 问题详细提示如下: E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarly unava ...

  3. Win7系统中如何查看当前文件被哪一个程序占用了

    https://superuser.com/questions/117902/find-out-which-process-is-locking-a-file-or-folder-in-windows ...

  4. 【命令】Redis常用命令整理

    doc 环境下使用命令:       keys 命令         ?    匹配一个字符         *    匹配任意个(包括0个)字符         []    匹配括号间的任一个字符, ...

  5. 关于java中的类的学习

    设计模式应该牵扯到类的分布排列了,尽管现在我只能这么表达. 下面来自段帅发来的视频课程中的整理: 类与类之间的关系 每天进步一点点 类是java程序中最小组成单位,要理解后才可以更能理解类继承,重载, ...

  6. UVa 10382 喷水装置(贪心)

    https://vjudge.net/problem/UVA-10382 题意: 有一个长为l,宽为w的草坪,在其中心线不同位置有n个点状的喷水装置,喷水坐标为p,喷水半径为r.求喷到所有草坪的最少喷 ...

  7. Codeforces Round #225 (Div. 2) E. Propagating tree dfs序+-线段树

    题目链接:点击传送 E. Propagating tree time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  8. ros 使用命令测试topic

    发布话题 $ rostopic pub -r /chatter std_msgs/String "test" 输出数据: $ rostopic echo /chatter data ...

  9. queue_01

    A.添加/移除 void queue::push(elemValue); // 尾部添加 viud queue::pop();  // 尾部移除 B.随机存取 C.数据存取 T queue::back ...

  10. 监督学习--k近邻算法

    2017-07-20 15:18:25 k近邻(k-Nearest Neighbour, 简称kNN)学习是一种常用的监督学习方法,其工作机制非常简单,对某个给定的测试样本,基于某种距离度量找出训练集 ...