5. 操作符重载与临时对象

发布时间 2023-06-04 23:12:42作者: cold_moon

operator overloading (操作符重载), 非成员函数 this

让我们回到刚刚的话题,我们刚刚谈到操作符重载,操作符重载是一个 C++ 的一个很大的特性,要讲的东西也很多,我们先回到前面的,有一张投影片啊,我们来看一个东西。这是最早的时候,我再说,一开始,其实我们一直都在进行的,就是在这个头文件,终在防卫式的这个声明之下啊,写这边的东西,那在这一张投影片里面呢,我这边列出来了,就是使用者可能这么去使用,我们现在所设计出来的复数这个 class,我们在这边看,可以看到对于复数的操作,我们都使用这种操作符,因为我们在学校里头学过的复数,也还可以加减乘除嘛,这里面的加减乘除是一样的,一组类似的动作,所以我这边只列出 +、+= 是 C++ 很独特的。我要提示我要引导大家去注意到的,就是对于这种数据,现在这个复数的数据的计算的、运算的操作,都是使用操作符。这个是在其它语言啊,或者在早先的 C 语言呢,你要对一个东西做操作,一定是设计一个函数。事实上在 C++ 里面,操作符就是一种函数,是可以让你重新定义的,这是它很大的一个特点。那因为我们认为对于复数这种东西,比如说你要相加,你如果写一个函数叫 plus,好像还不如你直接用 + 这个符号来做运算,所以C++就说那好吧,自然一点,我允许大家来写操作符。去改变它原来的定义,本来 + 可能只能加整数,现在我们可以拿来加复数,可以拿来加分数,如果你写了一个分数分子分母的分数的话,你也可以这么去做,你甚至可以加两颗石头啊,你写一个class叫做石头,那石头怎么相加,你是设计石头的人,由你来决定。现在我就是设计复数的人,我来决定复数要怎么 + ,那我们当然要把数学课本拿出来,说复数是怎么加,我们就把它实现出来好。现在我所以呢我们现在要来谈操作符重载。

再回到我们现在要讲的这个画面来,操作符重载。这个标题提醒我们一点,操作符重载有 -1 ,所以等一下会有一个 -2 跑出来。-1 跟 -2 差别在于,成员函数或者是非成员函数。也就是说你有两个方式,可以来写出这个复数的加法,现在呢我要把它写成一个成员函数,也就是在复数的 class 里头,我要去定义这样的一个函数。我们现在好好的分析一下,操作符是怎么被编译器看待的。像这样就是一个操作符,这种叫做二元操作符,两个操作数的有左跟右,所以我们会常常讲左数或右数指的是这个东西。编译器看待这么一行呢,它会把这一个符号作用在左边身上,如果左边这种东西有去对这个符号做定义的话,编译器就找到了,把这一行就定义成要去调用那个函数,那我们现在是焦点放在成员函数身上了。现在我就为复数写这么一个操作符,来应付这一件事情啊,因为我在设计的时候,我想象使用者可能会这么使用,我就写出这个函数出来,这个函数就是这个函数,这个就是这个,但是差别在哪里,我为什么要重新再写一遍呢。我把它隐藏在里面的一个东西挖出来给你看,就是这个灰色的部分,这个故事是这样的,所有的成员函数一定带着一个隐藏的参数,所谓隐藏就是其实你没有写,但是它在,这一个函数叫做 this。为什么取这个名字呢,谁调用我,谁调用这个函数,那个谁就是 this, 调用者。所以你看编译器把这个符号作用在左边,所以左边这个 c2 它就是 this。而 this 是一个什么,是一个指针,所以编译器会自动的为我们把 c2 的地址传进来,当成这个 this pointer,我们写代码不必写也不能写,你要写出来就错了,你不能写。 那这个this point 是我现在把它显示出来,放在第一个参数,一定是这样吗,不一定,不同的编译器行为都不一样啊,有的会把它放到最后一个参数去,反正我们写代码看不到,不影响我们写代码,但是放在哪里都无所谓,反正有这么一个东西。然后在这个 += 这个动作呀, += 是什么意思呢,是要把右边 + 到 左边身上去,所以我们在这里面,这个函数里面一定要看到左边,也要看到右边,不然怎么做操作呢。那现在你所看到的这个例子,又把这个右边 + 到左边身上的这一种动作,再包成另外一个函数放到上面来,其实不包,不把它包成另外一个函数放到上面也可以,你直接写,当然没有问题。现在是多了一层,冲上去,为什么要这么做,在这里你看不出道理,但是你可以感受它可以啊,本来该在这里做了,这样只能拿出来到另外一个地方去做而已。想必是这个函数这种右边 + 到左边的这种动作,大概在其它地方也会用到,所以我们独立出来,让其它地方也可以来调用。所以 右边要 + 到左边,那右边有了就是这个 r,左边也有了,就是这个this, 隐藏的。 但是 你不能够在参数列写出来,但是你在函数里面可以用它。我们就把左跟右呢传到另外一个函数去,是上面这里,那上面这里要怎么去做,把 右边 + 到左边 去,复数的加法是怎么加的呀,你看右边的实部 + 到左边身上,就这个第一行,右边的虚部也 + 到左边的虚部身上,这就是第二行,复数的加法,就是这样加的,数学课本告诉我们的。加完了以后就是已经改变了左边,因为我们正在最左边这个东西做动作,加完以后把左边这个东西 return 回去,这样就完成了,上面这个 return 回去,return 给谁呢,返返回给谁呢,是下面这个函数调用的呀,所以就返回到下面来,下面又把这个结果再返回来,就执行完了这个动作。这个就是对 += 这个操作符的设计。所有的操作符只要是两个操作数的,有左右两种,这种它的规则都这样,都作用到左边身上然后有一个 this pointer,就是刚刚的故事都是一样的,这种叫操作符重载。这个名字(__doapl)取得很奇怪,我怎么会取这个名字呢,其实我从一开始没有告诉各位,这一段代码是标准库里面的复数的代码,我是把它抓出来,拿掉一些我们用不到的东西,所以我们看的其实是标准库啊,一个很伟大的一个团队,里面都是很棒的人,它们所写的很正规的一个复数的设计啊。那个团队把这一个函数命名为这有 __doapl 我们会很奇怪它为什么这样命名呢,应该可以想象这个就是 do assignment plus,因为这种 左边 + 到右边,这种 += 的动作叫做 赋值的加法,也就是assignment plus。所以我们可以推想,它命了这个很奇怪的名称的原因是什么。所以在这个地方好传达了一件事情,任何成员函数都有一个隐藏的,this pointer。 pointer 指向东西,它指向谁呢,就指向调用者,谁调用我这个函数,那个 this 就指向它。这是我们的这一页,讲到操作符重载,我们继续往下看。

我们再一次回到一个主题,就是 reference。reference 用在传递参数身上,以及返回值的返回的方式,身上。有pass by reference 或者是 return by reference。好我又回到这个话题,我想谈什么事情,因为你可能会对这个写法感到疑惑,这是什么,这是你刚刚看到的那一个 + 的那个动作。这边传进来的左操作数是一根指针,返回的时候呢,这个黄色这个地方的写法是指针所指的东西,所以这个其实是返回一个东西,就一个 object 一个东西。可是返回的时候,它的声明却说返回的是一个 reference,这样你下面用星号上面用这个特殊符号,这样子对吗,对的。你返回的是东西是 value,但是接收端是怎么去接收它,你不必在乎。我们看这一句话,传递者无需知道接收者,接收端是用什么形式来接收,这就是好处,我们为什么要用 reference 的好处。各位想一想,如果你用 pointer 来传C++,也允许 pointer 来传东西,你用 pointer 来传的话,传的人必须知道现在传的是 pointer,要有一个特殊符号。但是现在回到画面上来,用 reference 来传的话,传递者无需知道,这个太好了。看看这个例子,这边,现在我们这这里有一个连串的加法啊,呃是我课要再引出另外一个故事,我们先看这个好了,把 c1 传到这个函数去, c1 其实是个value,它接受的时候是用reference来接受引用来接受,对传递者是无需知道的,说不定设计的人设计的不不够,它这个不够不够大气,不够厉害,设计的人是用value来接受这里,那也没关系,反正都不影响我使用者啊,这是好事情,其实是好事情,所以我们再一次感受哦,这边这个传递者呢,不需要知道接受者到底是怎么接受的,它也许是百value的方式来接受,也许是把reference方式来接受,我使用者都无所谓,不在乎写法都一样,所以回到这个话题来啊,当初是我认为大家可能会对这个语法有疑惑,我们再看一次,我们反正传回去返回呢就是object,至于返回去接收端,这里就是接收端,它要用什么形式接受,我不管如果它设计得够好,它就可能像这样用reference来接受,那速度就快,但如果它用value来接受,速度就慢,但反正我送出去的人都不管,我们好好地体会这一个地方跟这个地方啊,这个奇怪的符号其实是可以搭配的,好,然后我在这段画面,再引导大家来看另外一个故事,你好好的想这一个动作,c to c1 赋值啊, + 到c to身上,加完就完了,这个一加完这一个函数就执行完毕,没有人去在乎返回什么,其实,所以你可能会想,那我这个函数执行完,我在设计这个函数的时候呢,我的反复返回类型就写void的,这里也可以啊,没错,如果使用者确实只有这么用的话,你当初这个设计void是ok的,但是使用者也可能这样子用,如果你能想到这一点,你就会把你的克拉斯设计的更好一些,它怎么用呢,因为是从c以来上来的,这些程序员习惯或都知道可以这样连串的赋值,哦所以它也很可能对你的复数,它也这样子连串的做动作,那我们来好好分析一下,这个这一串是先做什么事情啊,那这个得查书喽,我的印象是 c1 先付到,先 + 到 c2 身上, c2 再 + 到c3 身上,c three身上,那好所以 c1 + 到c2 身上,这个这个执行完了,这个就是这个函数,它执行完了之后的东西就很重要了,不能是boy的,因为这个东西马上还要当成左直右直右, + 到c3 身上,所以这里就不能设计微博,要不然的话这一行就通不过,我们在一些操作符重载上面呢,等一下还会出现另外一个例子,也是这样的考量,当使用者没有连串使用的时候,诶,但是当使用者连串使用的时候呢,你要多做一些思考啊,我现在谈的是 += 这个操作符的返回类型,不可以是void毁的,是这个原因,好我们继续往下,这边标出来就是在我要设计我的这个复数的class,里面的有两大段,我们很快地回去看看,我们不要迷失了,当初在这边说一个头文件里面,我要设计这一块跟这一块,那这一块一这一块呢已经讲完了,这就是类的本体,class的本体讲完了,我们现在是在讲本体以外的这一段,所以这一段这里面存在的一定都是函数,要不就是这一个类class的成员函数,那就是这种全名,要不就是全局函数,全域全域global函数,那它的函数名称一定不会带着class name在前面,一定不会,所以我们一看class name,function name啊,这是function name,一看方训练就会知道这是成员函数呢,还是这是全额全域的函数,现在一直都关注在现在二这个区域好,回到刚刚那一页,刚才讲到这里,这是二二里面的某一段,我们往继续往下二里面的段,那这个函数你看它没有带class的名称,所以这是一个全域全局全域函数,global啊,这函数非常简单,做什么呢,下面是用法,我想要取得某一个复数的实部,或某一个复数的虚部,是现在上面这里,好把要注意的第一件事情是,class尽量用reference来传速度快,那在这个函数里头呢,就通过这个传进来是x去取得实部啊,就得到了这两个函数非常的简单,在技巧上没有特别要注意的地方,好我们再往下看,这里是二至三啊,就继续看,我们有一大堆的函数要看,这里又出现了操作符,重载,刚刚讲的那个形式是成员函数,现在讲的形式是自二非成员函数,我们看看右手边这里,如果使用者这么写的话,它使用你的复数,它这么写的话,100000加c9 编译器就要去找,看看有哪一个函数可以符合这个加的动作,它也许先去找成员函数,也许先来找非成员函数,我也不知道它先找谁,但是先找谁都无所谓,因为你不能写两个,你不能写出这两个,然后看它先找谁啊,这样是不行的,你只能写两个里面的,其中一个刚刚已经示范,在 += 那边示范的成员函数的写法,现在看看非成员函数的写法啊,我们现在应付的是加这个动作,哦你看到了,这里有三个版本,为的是什么呢,因为我们在设计的时候,认为使用者可能会这样子加,复数加复数或者是复数加一个十步,或者是一个十步,也就是在这里就double值加一个复数,因为数学上告诉我们可以这么加一个复数,可以跟一个实数加在一起,好我认为使用者可能会这三种书写法,于是对应的我就必须写出,你看这边讲,为了应付client客户的三种可能用法,我们这里要写出三个函数,好这三个函数差别在哪里,因为一一对应嘛,复数加复数,那这里的两个参数就都必须是复数,如果是复数加double,指这个五在这里被视为double 5会被变成五点啊,那就传进来复数加double这个函数就是复数加double,那如果是double加复数呢,所以下面这个函数是double加复数,我们用三个函数来对应,右边三种可能适用,这是我这一页要传达的,事实上在数学里,数学里头还可以复数,直接加复数加虚数,虚数加复数等等等啊,如果你作为设计者,你要应付使用者的所有这种可能的话,那你还要继续写下去,加你还要继续写下去,好所以呢对于非成员函数的这种操作符重载,我们的写法是这样子,跟前面的不同在哪里,前面有this point,现在这个是这个是全局函数,全域全局global,它没有this point,o我们继续往下看,还是同呃,画面不同了,但是我还是要讲同样的这三个家,我要谈的是它们返回的为什么不是reference,不是说最优先考量要是reference吗,但是这三个蓝色的部分是value return by value by vision,没有摆reference好啊,它比较差,比较慢,但为什么这三个不行,reference呢,这边想了绝不可以啊,为什么,因为它们返回的必定是一个local object,这句话什么意思,你现在把左边和右边相加,加的那个东西要放在哪里,目前没有那个东西,先前那个例子是把右边 + 到左边身上,而左边已经存在了,现在不是这种情况啊,所以加好以后要放到哪里去呢,势必要在这个函数里面先创建一个出来,准备放结果,所以是在这个函数里面创建出来的,这三个函数都是这样,那在这里面才创建的,离开这个函数之后,它就它就死亡了,所以这种东西你不能把reference传出去,一传出去之后,这个自己死掉了,那外界要用就用到了错误的东西,啊所以我们就是这样子在分析一个方形,能不能return by reference,就是这样子的思考,所以我们得到的结果啊,我们就可以确定三蓝色的这三块一定要return by value,by value,现在我们来看看诶,那刚刚不,是说应该在函数里面创建了一个东西吗,这里怎么好像好像没看到,这里有个特殊语法,这是类的名称,class a complex就是一个tab name,tab name后面直接加小括号,对很多人来讲,这个语法是陌生的,其实很,但是这个在标准库里面很常见到,我们必须熟悉它一个type name,直接加小括号,就好像你写int直接加小括号,唉过去你习惯的是i n t,然后一个变数名称,比如说叫i,然后你去用这个i现在是不一样不一样,好我们现在回到这里来,现在这个你看这是一个type name,直接加小括号,只不过里头有参数就是了,下面也是一样,type name小瓜号,下面也是type name小瓜号,那type name加小括号就是要创建临时对象,什么叫临时对象呢,它临时才要的,我临时才要的,所以我不想给它名称,要临时的嘛,它的生命到下一行就结束了,那下一行就结束了,而且没有名称,这适合我们现在这样子的用法吗,适合,因为我现在只是要创建一个一个东一个空间,一个东西来放家的结果,然后马上要返回这边,马上return返回了,所以虽然生命很短,虽然没有名字都无所谓,至于这个临时对象要放什么东西,那就是这三个函数所要做的事情了,复数加复数的话,我们就把实部加实部,虚部加虚部,以此类推,比如说你有一个十步double x算是十步好了,虚部就是零嘛啊这个十步要加复数的实部,虚部虚部是零零,不用加,这里没有加的动作,所以这一页主要传达的是什么,是临时对象,然后语法要怎么写,而这种东西临时对象呢,在这个例子是适用于复数的加法,这三个函数身上,你看右边这样也是临时对象,黄色的这一部分,其实这个语法就是左边,它只是这这也是type name加小括号,只不过它没有参数,没有参数,那就是默认值了,我们前面已经讲过构造函数有默认值,那这个就是零零,那下面这个呢也是一个临时对象,它的内容是四汉武,这两个是没有名称的,上面这两个是有名称的,那下面这两个没名称的,它们的生命呢进行到这里已经没有了,进行到下一行,这两个都不见了,都不见了,这个是临时对象很特殊的一种语法,所谓特殊是其实一般人可能少用啊,但是标准库确实用的很多,所以要注意,好我们继续往下看,仍然在操作符重载身上,那操作符重载的语法要注意的,其实在前面都已经有代表性的,都讲完了,那么这边又提出两个,这也是家啊,跟刚刚是重复吗,那这个是减减,刚刚都没出现过,呃,其实它跟前它这个不是加这个叫正号,这个叫负号,它的用法是这样,像下面这样子,我们的创建了一个复数之后,可以把它取反或者叫反向negate,数学上有这样的运作吗,那也可以取证啊,证号,所以上面的加正啊,这就不应该念加了,应该念正好啊,正跟负是这样子用的,那编译器怎么知道你,你都是这个加这个符号,它怎么知道你是这是这时候是正号,那边是加法,这是怎么分呢,看参数就知道了,这个只有一个参数的,在我们的数学符号里头只有一个参数的,那一定是表示正号,不是要表,不表示它要加,它要加谁呢,所以靠参数的个数来表现出来它们的不同,好这里有个有趣的事情,像负号来讲,你传了一个复数进去,负号表示要做出一个新东西,因此一定在这个函数里面要创建一个空间,来放新的结果,这是刚刚一再强调的,所以这里又是一个临时对象,临时对象local函数内的这个绝对不能return by reference,所以这个是return by value,这是刚刚的那个逻辑,完全延伸,完全没变,我们是要做正号,做正号就表示都不变都不变,所以并没有一个说有要产生一个新的结果,没有啊,没有这件事情啊,所以并没有所谓的local object在这里诞生没有,因此应该可以传回reference,应该可以,那为什么这里不写呢,这不是你写的吗,不是我写的吗,不这不是我写的,这一个我刚刚提过,是标准库里面有确实有这么一个复数,我把它抓出来为大家讲解,这个不是我写的,那你可能会问我,那它为什么写成这样,标准库这么厉害的,这些人会写错吗,那个很难说它并没有错,它只是写的不是最好,它并没有错,这个结果是不会错的啊,所以这个等于说带给大家一个习题,我前面提过,你这个课程学完之后,你可以下载,我们有相关的网址,你可以下载这个例子,你可以把这个地方改成reference,看看它可不可以正确运作,我相信是刻意的,这里,标准库那一些很棒的人,它们所写的标准库并不是圣经,不是说呃它绝无可挑剔之处,不是,好这一页带给我们的是这些东西,我们再往下看,继续下去的全部都是炒作服重载啊,主要是因为我们现在设计的这个复数,它是一个数学上的东西,大家都习惯用熟悉的符号来操作它,所以这边有什么等号,就a跟b等不等,两个复数等不等,那等不等,这件事情呢呃用法是像这样,我举了三个例子,复数等不等于另外一个复数或者复数等,不等于某一个double值或者某一个值,double值等不等于复数,有三种可能,所以我们要写出三个函数来对付它,来应付它,就这样其它的考量都跟刚刚相同啊,不我们要考量什么啊,参数的传递快不快啦,有没有传reference,返回的时候快不快啦,有没有返回reference这个例子没有返回吗,那为什么,想想刚刚所讲的话,所以在语法上已经没有新的要讲了,这个是比较两个函数的等不等,而不是两个函数,两个复数相不相等,再往下这个也是比较相不相等,这个是不等于刚刚那个是等于,其它的考量都一样,所以这里也没有新东西,要说,这一页出现了,这这也是我们这个整个例子的最后一页,整个程序快要结束了,一个复数的计算其实很多加减乘除啦,那些三角函数一大堆啊,我只抽出几个可以代表性,我要讲的语法的部分拿出来讲,我们看看啊,大家印象很深刻的复数会有所谓的共轭复数,共轭复数是什么意思,就是实不相等,虚部呢正负号相反,这个叫共轭复数好,那我们就来设计这么一个函数,construction共轭复数,那它应该接受一个复数进来了,那我们在这里应该是在里头产生一个新的空间,准备容纳执行结果,这执行结果会是什么呢,实部就是原来的实部,虚部呢再加一个负号,这是共轭复数,这个在语法上也没有什么独特的地方,用法呢,下面是一个用法啊,我本来有一个复数,我要调用这个函数吗,那这是成员函数吗,这不是,其实你也可以考虑把它写为成员函数,任何一个操作你都有两种想法,设计为成员函数,或者设计为全局函数,全域全局函数都可以解决问题,也不一不一定谁就一定比另外一种好,不一定都要看状况,在这个例子里面把共轭复数设计为global啊,全局函数,所以用法是这样了,我调用这个函数,把我的参数,我的一个复数传进去,会得到一个结果,那我在这里是把这个结果输出输出到cl的,也就是你的屏幕去,剩下最后一件事情,我们整个例子的最后一件事情要讲这个操作符,这个操作符的重载有比前面有一些特别的地方,小于小于,我们再一次分析这个这种既然小于小于,就是又要把右边输出到左边身上,我们再一次分析它的语法啊,假设你就是编译器,你看到使用者这么用的话,编译器会把这个操作符号作用在左边身上,是不可能作用在右边身上的,接下来语法就没有这种作用在右边身上,这种语法,所以它会把它作用到左边身上,左边是什么,是cout c out是什么,是标准库定义的一种东西,我们现在不去深究它,当它你把它想象,它代表屏幕就要输出到屏幕去,这个是标准库早就写好了,所以你这个符号作用在它身上,也许是10年前写好的ceo,它不可能去认识你,现在才发展出来的复数这种东西,它顶多只能认识嗯,当时既有的那是什么呢,就是building的内置的那些类型,它不可能认识新的这种类型,所以对于小于小于这个叫做output operator,我们绝对不要想把这个这一种操作符,写成一个成员函数,操作符有两种写法,一种是成员函数的写法,一种是非成员函数的写法,现在这两种本来我说你都可以考虑,但现在我告诉你,对于这种特殊的操作符,你只要选,你只能选一种,就是全局的那一种写法,格罗布的那种写法,原因刚刚已经告诉你了,好那我们就开始来写了,所以就写出这么一个函数,operator小于小于这地方都可以,有空号或没有空格都是一样的,前面我提过C++跟c的写法,它都是free phone自由形式的啊,你要加几个空格都无所谓,现在我们来看看这是一个global的函数,那它有两个参数,这两个参数就是使用者这么用的时候的,左边和右边,好右边必须是一个复数,这我们都知道了,因为我们现在就是要输出一个复数嘛,所以右边呢也就是第二参数啊,这里是一个复数,很好,而且是传的是引用速度快,传进来以后呢,只是要输出而已,没有要改内容,所以这边加constant,一切都很好,那第一个参数该怎么确定它,第一个参数就是这个see out,c要的是这是cl的这个object,这个对象它是什么type,也就是它的classname是什么呢,那要去查手册,这不是你写的,也不是我写的标准库的,非要去查手册,查到的结果是c out的是什么,就是一种o stream这种东西,这个叫output stream,我们现在也不必管这是什么,反正c2 就是这种东西,所以我们第一参数确定下来了,它必须是这种type,好然后开始考虑了,那东西传进去是要传引用呢还是传值呢,首先考虑传引用,看有没有副作用,是不是可以传引用,可以,要不要加constant,这里第二个考虑在这里不可以加constant,为什么,加了constant表示这个os o s代表o,而不是stream吗,os传进来之后不可以改,我再讲一次,当你在设计这一块的时候,你如果这里加constant,意思是传进来的,这个os在这个函数里面不可以被改变,本来你想象中对呀,我根本就没有要改这个传进来的,stay out,没有,我没有要改它,也这里也看不出来,我又改它,但实际上是你在这个函数里面,把各种东西往c out scout,也就是这里的os d的时候其实没丢,任何东西都在改变这个os的状态,这可能让你感觉有点抽象啊,因为毕竟os这种output stream不是你写的,不过事实是现实是如此,每一次输出都在改变它的状态,它里面的资料,由于这个因素,所以我们设计这个操作符的时候,这里不能加constant,这里要注意,我们是在前面呢讲了那么多的操作符重载,现在碰到这个操这个操作符很特别,这个可想完呃呃呃设设计的这个方式呢,想完毕了,在这个函数里面要做的事情,你想怎么输出,你就输出,你就怎么输出吧,你现在想把你的复数怎么输出呢,我可能会想要输出复数,有实部虚部,我可能会想要输出小括号,十步斗点虚部再加一个i,数学上都是这样表示虚部是有一个i嘛,然后再加上右边的小括号,或者另外一个人,它想我的叔叔不想这样,我是中瓜号,实部空一格,虚部不加哀,再一个中挂号啊,它想这么输出都可以,你想怎么输出,你就怎么输出,现在这个例子我们看看啊,这是标准库提供的一个程序啊,它是怎么输出的,它先写一个小括号,再写出十步,再写出一个逗点,然后再写出虚部,再写出右边的小括号,也就是这样,啊这是这一个函数的设计,它想设计成这个样子,这些刚刚我提过这些小括号的输出,十步骤点的输出都在改变,现在叫os的这个东西,也就是output stream的状态,只是你可能看不出来,全部输出去,出去之后,现在我们来检讨返回的类型,你想一想这一行,你把一个复数啊在这里已经取得它的共轭复数,那还是一个复数吗,你把它输出到c2 的去,输出完了之后呢,谁在乎结果,已经输出到屏幕,这就是结果了,没有人再去在乎这个函数传回什么东西,don't care,所以按照道理说,这样思考的话呢,这个函数它的返回类型我们可以设计为void,ok没问题,但如果你想远一点,你的使用者可能这种连串的输出,啊有人很习惯这么用,这是延续过去以来的习惯,为了让它能够获得满足,我们就返回的,不能是boy的这个输出是什么样的,次序是先输出 c1 输出完了之后看得到什么,还要能够接受右边这一个,所以啊再讲一次,你看把希望丢给c out,得到的结果,还要再能够继续接受这个小鱼小鱼,可见这个函数执行完的结果又要是c out,这种东西,它不能是void,也不能是其它,它就是还要再传回c1 ,这样我们就确定下来了,所以这里呢返回的仍然是scout这种东西,就是output stream,至于返回的是by value还是by reference,再思考一次,最优先就是by reference,然后回来看看,这东西是这个函数里面的local的东西吗,不是啊,所以没问题,要不要加constant返回类型,这个要不要加constant,在这里不可以加,在这个例子里头,你看 c1 丢给c2 之后得到的结果,得到的结果还要继续接受右边的的这个参数啊,又要去改变这个这个c奥特本身,所以需要的不可以是constant,好这个图在这个地方有问你可以吗,在这个地方问你可以吗,问的事情就是如果返回类型改为void的呢,我们刚刚其实都讨论过了,在这里现在把左边改成右边,把这个返回类型改成void,可以吗,当然如果你改成void的,你就不要return了啊,这样一直一并改的一定改,可以吗,不行,整不行是太武断了啊,如果使用者只是这样用就可以,但是如果使用者是连串输出就不行,所以作为一个好的设计,你当然要去思考使用者可能怎么去用你,你统统都要去满足它,这是我们的呃,在我从标准库抽取出来的这一个啊,例子的最后一部分,你上完这个课之后,你将会获得的代码是这两个档案和文件,好前面我们提过类class有经典的,有两种分类,一种是带指针的,一种是不带指针的,我们现在把不带指针这一部分讲完了,当然这个过程里面还有很多的更细节的部分,或者是联想拉出去的更多的部分,那个我们在后头继续再把它加上去,现在的第一要件就是让大家能够,很能够在很短的时间里面,写出一个复数这样的类出来,并且一起手,就是一个一个一个很大气的一个程序,我们回到最前面来啊,最重要的一个观点呢再做一次整理,然后这一个主题就结束,我们就会进入下一个经典的例子,好我来找出最适当能够代表的这个投影片,这是很前面出现过的,我们很快的想一想哦,设计一个class要注意什么事情,构造函数的这一个nitialization list,一定要会用,不会用的话,我会认为你可能训练不够精良,虽然最后结果可能一样啊,你用或没用结果一样,第二件事情,函数该不该加constant一定要考虑,该加就要加万,因该加,而你没加,可能会有副作用,跑出来,第三件事情,参数的传递尽量考虑pass by reference,像这样就是pass by value,啊尽量考虑by reference,而且要不要加constant,要考虑,第四下一件事情,return的时候return这就是return by value,这个就是return by reference,这都要去考虑,再下一个呢你的数据,尽可能的几乎没有例外啊,要放在private里头,而你的函数绝大部分要放在public里头,因为你的函数主要是主要啊是被外界调用,这就是我们谈到的复数这个例子啊,所交代的几个,请大家要特别注意,这地方好,我们这个单元到这里,