《C++面向对象高效编程(第2版)》——3.14 为参数选择正确的模式

3.14 为参数选择正确的模式

C++面向对象高效编程(第2版)
尽可能避免按值传递大型对象。对于基本类型和小型对象,可按值传递。复制对象的开销很大,但是,如果主要考虑安全问题,则应坚持按值传递。

需要传递对象时,不要传递指针。
`
void f (T* object);`
(1)指针无法保证它确实指向某对象,它很可能是一个空指针。

(2)如果被调函数需要将真正的对象作为参数,则传递引用,而不是指针。这可确保不出现问题,被调函数无需检查空引用(因为不可能出现这种情况)。

(3)如果希望被调函数在对象中写入(输出形参),则传递引用,但不是对const的引用。

(4)传递引用并不意味着将对象的所有权移交给被调函数。主调函数仍然拥有对象(且对其负责)以及与该对象相关的内存。如果被调函数希望主调函数放弃对象的所有权,应在文档中清楚地说明。否则,双重删除(double delete)会导致程序无法正常运行。[多次释放(在C++中为delete,C中为free)一个指针所指向的动态内存地址时,会发生双重删除。使用new()分配的内存只能使用delete操作符删除一次。但是有时,由于程序出错,相同的指针会被多次删除。]

(5)被调函数需要检查指针是否为空,才能使用它。这样的接口非常不好用,而且难以追踪。如果确实需要,应在文档中清楚地说明,以免混淆。

当传递基本类型参数时,要坚持使用值参数(value argument)。传递指针和传递整数的开销一样,但是,按值传递更安全。

在可以使用默认值参数的地方,尽可能使用默认值参数。它们不仅包含更多信息,还有助于理解参数的用途和减少了客户的负担。客户只需传递较少的参数。

尽量对参数和函数使用const限定符。前面介绍过,编译器能识别const限定符,这样做让编译器也参与其中,使得程序更加强健稳定。

如果希望在参数中使用多态(后续章节将介绍),则必须使用引用或指针参数,不能使用按值传递。此规则也适用于返回值(在下面说明)。

注意:
无论何种规则,都有一些例外,特别是将指向基本类型的指针作为参数时。即使不涉及转移所有权,也应按照惯例,传递指向基本类型(特别是字符指针,char*)的指针。这是因为指针允许导航(使用++和--操作符),而引用并没有这种灵活性。在大多数情况下,这样的指针都用来作输出和输入/输出形参(参见strcpystrcat等库函数)。如果在接口中发现使用未转移所有权的普通指针时,不要感到惊讶。不过,这样的接口必须在文档中详细地说明。由于指针的灵活性,甚至当传递未转移所有权的对象时,在某些情况下也要使用指向这些对象的指针,而不是引用。方法可以要求指向对象的指针参数,但要带有默认值NULL,这允许主调函数在调用方法时可省略参数。在这种情况下,指针将用于指出哪个参数是可选的,而引用参数却很难做到这一点,因为它没有独特的值来区分非法引用(每个引用都是合法的引用)。因此,要养成遵循一些规则,但同时也记住例外的好习惯。无论如何,都要在文档中清楚说明这样的接口,以避免出现混淆。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

时间: 2024-08-04 10:11:22

《C++面向对象高效编程(第2版)》——3.14 为参数选择正确的模式的相关文章

《C++面向对象高效编程(第2版)》——导读

前言 C++面向对象高效编程(第2版) 面向对象软件开发已逐渐成为开发软件的首选.优秀的面向对象软件开发人员.设计人员.系统架构师对其需求与日俱增.要想成为一名成功的面向对象编程(OOP)人员必须忘却(摈弃)多年来面向程序编程的习惯,从新的角度分析问题. 面向对象编程要求程序员和设计者非常熟悉一些基本范式或概念.理解这些范式是在面向对象软件领域打下牢固基础的基本要求.支持OOP的语言都必须支持这些基本范式.换言之,学习OOP,简单地说,就是学习许多语言(如C++,Eiffel,SmallTalk

《C++面向对象高效编程(第2版)》——4.2 无用单元收集问题

4.2 无用单元收集问题 C++面向对象高效编程(第2版) 在我们讨论无用单元收集1(garbage collection)之前,先了解一下何为无用单元(garbage),何为悬挂引用(dangling reference). 4.2.1 无用单元 所谓无用单元(garbage),是一块存储区(或资源),该存储区虽然是程序(或进程)的一部分,但是在程序中却不可再对其引用.按照C++的规定,我们可以说,无用单元是程序中没有指针指向的某些资源.以下是一个示例: main() { char* p =

《C++面向对象高效编程(第2版)》——4.6 对象赋值的语义

4.6 对象赋值的语义 C++面向对象高效编程(第2版) 赋值与复制的操作非常类似.在C++中,绝大多数的复制操作都由语言隐式调用(当对象按值传递或按值返回时).当通过现有对象创建新对象时,也进行了复制操作(但不是很频繁).与复制相反的是,赋值是必须由程序员显式调用的操作.然而,在Eiffel和Smalltalk中,赋值和复制操作都由程序员显式调用.这也是基于值的语言与基于引用的语言之间的区别. 在C++中,对于对象和基本类型赋值都具有相同的含义.把基本类型变量赋值给另一个(兼容的)基本类型变量

《C++面向对象高效编程(第2版)》——2.21 确保抽象的可靠性——类不变式和断言

2.21 确保抽象的可靠性--类不变式和断言 C++面向对象高效编程(第2版) 任何抽象都必须与客户履行它的契约(contract).当客户使用类时,他希望类的对象像其发布描述的那样运行正常.另一方面,类的实现者必须千方百计地确保对象运行正常.但是,类只有在客户履行自己那部分契约后,才能正确行使它的职责.例如,类的成员函数可能要求传入的参数为非零指针(non-zero pointer).只有满足此前提条件,成员函数才能保证它的行为.因此,客户必须履行一些义务.换言之,如果客户履行了她那部分契约,

《C++面向对象高效编程(第2版)》——2.30 has-a关系的重要性

2.30 has-a关系的重要性 C++面向对象高效编程(第2版) "has-a"关系(也称为关联.聚集.包含.组合)是在OOD(面向对象设计)中频繁使用的重要关系.但是,许多设计者和程序员都没有很好地理解其相关性,从而导致复杂僵化的设计和不必要的继承. 在OOD阶段,软件的复用主要通过两种方式完成:继承和包含.它们各有优缺点.优秀的设计者了解它们的局限性.优点和代价,可以灵活自如地应用它们.继承将在第5章.第6章以及第二部分的第12章中详细讨论. 包含是一项强大的设计技术,它比继承更

《C++面向对象高效编程(第2版)》——2.27 关联

2.27 关联 C++面向对象高效编程(第2版) 关联表示对象与不同类之间的结构关系(structual relationship),大多数关联都是二元关系(binary relation).类之间的多重关联(multiple association)和类本身的自关联(self association)都是合法的(见图2-19). 关联可以有一个名称,表明阅读方向的箭头为可选.注意,方向箭头为可选,但关联名必须显示.关联在不同的方向可以有不同的名称,但是,大多数情况下,没必要注明(特别是在已标出

《C++面向对象高效编程(第2版)》——3.2 类要素的细节

3.2 类要素的细节 C++面向对象高效编程(第2版) 3.2.1 访问区域 客户可以访问在类的public区域中声明的任何成员.我们可以把该区域看做是通用公共(general public)的接口,它没有任何保护,是类限制最少的区域.一个设计良好的类绝不会将数据成员包含在public区域,该区域只能包含成员函数.如果在public区域包含数据成员,那么无需类的实现者,仅通过编译器即可访问这些数据成员.这违反了数据抽象和封装原则.这也是我们为什么总将数据成员放在private或protected

《C++面向对象高效编程(第2版)》——第2章 什么是数据抽象

第2章 什么是数据抽象 C++面向对象高效编程(第2版) 面向对象编程的一项基本任务是创建带有适当功能的类,并隐藏不必要的细节(即抽象数据).下面,我们将用一个现实生活中的例子来解释数据抽象的概念. 绝大多数人都见过影碟播放机(laser disc player)(或LD播放机).现在,提出一个简单的问题:设计一个影碟播放机,要求易于使用和修改,可后续添加更多有用的功能. 注意: 如果难以理解影碟播放机,可以用CD播放机代替LD播放机,其设计原理类似.实际上,影碟播放机的功能是CD播放机功能的超

《C++面向对象高效编程(第2版)》——1.5 什么可以作为类

1.5 什么可以作为类 C++面向对象高效编程(第2版) 用简单的例子详细讨论类和对象非常容易,但是难点在于如何为给定的问题找出合适的类.我们必须理解类代表什么,何时将问题中的某些部分转化为类,而非数据,反之亦然.根据我们的定义,类拥有一组对象的共同属性(或者特性).怎样的共同才是共同?何时说这是一个类,而不是另一个类的对象?这些都是我们在学习OOP时会遇到的,和真正关心的问题. 当我们决定创建一个类时,第一个问题就是"是否确实需要这个类的多个实例?",如果答案为"是&quo