条款21、函数必须返回对象时,不可返回引用
因为前面讲过,函数参数传值方式的效率没有传引用的方式效率高,因此,我们便会萌生,函数的返回值是否也是如此。
然而,并不是这样的,当我们用引用返回函数的值时,有时会导致致命的错误。
考虑下面一个表现有理数的类:
这个类的 operator* 函数是返回的是以值得方式进行传递的对象,倘若我们将这个函数改为以引用的方式进行传值。则我们必须为返回的引用建立相应的对象。
建立对象的方式不外乎两种方式,一种创建是在stack空间里面,而另一种则是创建于heap上。
倘若我们将对象建立于栈空间上,则一般我我们的对象在在局部的作用域内建立的,倘如我们的函数是这样改写:
倘若我们的函数像上述方式进行改造,那么我们则犯下了一个致命错误,那就函数返回了一个局部对象的引用,在函数局部作用域的变量或者对象将会在函数结束后被销毁,此时我们返回的引用的实质是对象已经不存在,这种情况显然会发生未定义错误,显然这是不可行的。
对象的建立还有第二种方式,那就是我们将对象建立于heap上,采用动态内存来分配空间,于是可以写出如下的代码:
这时问题来了,我们对象是在堆上建立的,那么当不在使用对象时由谁来delete这个对象,即使每次我们使用完该对象我们都记得将他delete,但是对于以下的情形我能-们由又能t如何处理?
我们显然调用了两次该运算符,但是最终我们的对象却只有一个,我们建立了两个对象,我们最后却仅是只能删除一个对象,我们这样显然会造成内存的泄露。
我们如果采用static变量,我们则可以避开返回局部对象的引用的问体,于是就有这样的代码:
但是这种情况存在很多的问题,如果我们进行如下操作:
这样我们将会发现,如果我们将会是用相同的对象做比较,显然这两个对象的始终是相等的,两个对象都是operator* 内部的哪个static对象。因此这种方式显然也是不合理的。
所以当我们的对象必须返回对象时我们不能返回对象的一个引用。我们的代码可以这样写:
条款22 将成员变量声名成为private
处于封装性和代码的可维护性的角度,我们的类成员变量应该尽量的写成private,然后对每个变量的访问,我们向用户提供接口,使得用户可以设置和获取该变量的值。
用户不能直接使用我们的代码,这样当我们对代码进行维护时,我们就不需要对用户的代码进行修改,我们只需要保证我们的接口不变即可。