若所有的参数皆需要类型转换——请为此采用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. NOIP Mayan游戏 - 搜索

    Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个7行5列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定的步数内消除所有 ...

  2. Python3基础 while 循环示例

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  3. redis linux版本自定义安装目录、注册服务、自启动设置、一台计算机安装多个redis

    自定义安装目录并安装 1.mkdir /usr/local/redis 2.下载redis到 /usr/local/src/,解压,进入解压后的目录 3.安装到指定目录 make PREFIX=/us ...

  4. Visio 画图去掉页边距(图形四周的空白区域)的解决办法

    步骤如下: 1.打开Visio对象后在[文件]菜单[选项]菜单项上单击,然后单击[自定义功能区]. 2.在[自定义功能区]的主选项卡中找到[开发工具]复选框,打上勾,单击确定. 3.在Visio对象的 ...

  5. [codeWars] - 8kyu的简单复习

    https://www.codewars.com/kata/5aa736a455f906981800360d public class Kata { public static boolean fea ...

  6. 【Python】【问题集锦】

    1. 用pycharm安装第三方包失败,报类似于“sort"的错误,就转战终端 2. Mac终端安装第三包失败,报类似于“ PermissionError: [Errno 13] Permi ...

  7. Nginx 多重条件判断

    server{ listen 80; server_name xxx.com; index index.html index.htm index.php admin.php; root /home/w ...

  8. DrawDibDraw__ZC测试

    ZC: 先把 自己尝试成功的代码 记录下来,不要 弄没了之后 又忘了怎么弄... ZC: 代码 有点乱,没整理.没写 哪些是 原来MFC里面的 哪些是我自己写的,参考上一篇文章来看吧 1.VC6 的一 ...

  9. input 输入框只能输入纯数字

    1.onkeyup = "value=value.replace(/[^\d]/g,'')" 使用 onkeyup 事件,有 bug ,那就是在中文输入法状态下,输入汉字之后直接回 ...

  10. NotifyIcon实现托盘程序

    NotifyIcon 控件的常用属性属性:Icon类型:System.Drawing.Icon说明:将在系统任务栏中显示的图标.可以在设计时指定,也可在运行时动态指定.属性:Text类型:String ...