《Effective C++》Item19:设计类之前需要深思熟虑

本条款在原书中的名称是:设计类犹如设计类型。

C++就像其他支持面向对象的语言一样。当我们定义了一个新的类,也就定义了一个新的类型。身为C++程序员,我们的许多时间主要用来扩张我们自己的类型系统。这意味着我们并不只是类的设计者,还是类型的设计者。重载函数和操作符、控制内存的分配和回收、定义对象的初始化和析构等等,这些操作全部交给我们来控制。因此,我们应该带着和“语言设计者当初设计语言内置类型时”一样的谨慎来研讨类的设计。

设计优秀的类库是一项艰巨的工作,因为设计好的类型是一项艰巨的工作。好的类型有自然的语法、直观的语义,以及一个或多个高效的实现品。在C++中,一个设计不良的类恐怕无法完成上述的任何一个目标,甚至类的成员函数的效率都可能会收到它们“如何被声明”的影响。

那么,如何设计出高效的类呢?首先我们必须要了解正在面对的问题。几乎每一个类都要求我们面对以下的问题,而我们所给出的回答往往直接影响最终的设计规范:

  • 新类型的对象应该如何被创建和销毁? 这会影响到我们的类的构造函数和析构函数以及内存分配和释放函数(即operator newoperator delete)的设计。
  • 对象的初始化和对象的赋值该有什么样的差别? 这个答案决定我们的构造函数和拷贝复制运算符的行为,以及二者的差异。很重要的是别混淆了“初始化”和“赋值”,因为它们对应于不同的函数调用。
  • 新类型的对象如果在调用时进行值传递,意味着什么? 记住,拷贝构造函数用来定义一个类型的值传递该如何实现。
  • 什么是新类型的“合法值”? 对类的成员变量而言,通常只有某些数值集是有效的。那些数值集决定了你的类必须维护的约束条件,而这也就决定了你的成员函数(特别是构造函数、拷贝复赋值运算符)必须进行的错误检查 工作。它也影响函数抛出的异常、以及函数异常明细列表。
  • 新类型属于某个继承体系吗? 如果这个新的类继承自某些既有的类,那么就要受到这些类的设计约束,特别是受到虚函数和非虚函数的影响。如果我们允许其他类继承这个类,那会影响到我们是否要将其中的成员函数(和析构函数)声明为虚函数。
  • 新的类型需要进行何种类型转换? 类存在于其他很多类中,因而彼此是否允许进行相互转换?如果希望允许T1类型对象被隐式转换为T2类型,就必须在类T1中写一个类型转换函数operator T2,或者在类T2中写一个类型转换构造函数T2(T1)。如果只允许explicit构造函数存在,就得写出专门负责执行转换的函数,且不能为类型转换运算符或是类型转换构造函数。
  • 什么样的运算符和函数对此新类型是合理的? 这个问题的答案将决定我们在类中添加哪些函数,其中某些是成员函数,有些可能是其他函数。
  • 什么样的函数应该不被外界所使用? 应该将这些函数声明为private
  • 谁该取用新类型的成员? 这个问题帮助我们决定哪个成员为public,哪个成员为protected,哪个成员为private。它也帮助我们决定哪一个类或者函数应该是友元,以及它们是否应该作为嵌套类出现。
  • 新的类型那个具有哪些非功能性需求? 它对效率、异常安全性以及资源运用提供哪种保证?在这些方面提供的保证将为类的实现添加相应的约束条件。
  • 新的类型是否可以一般化? 或许我们其实并非定义一个新类,而是定义一整个具有相似行为的类族。如果这样,我们就不该定义一个心类,二是应该定义一个新的类模板。
  • 真的需要定义一个新类吗? 如果只是定义新的子类以便为现有的类添加机能,那么说不定单纯定义一个或者多个非成员函数或者模板函数更能够达到目标。

上面的这些问题不太容易回答,所以定义出高效的类是一种挑战。然而如果能设计出至少像C++基本类型一样好的类,那么一切汗水就都是值得的了。

【注意】
在设计一个新的类之前,请确定已经考虑过本条款中所涵盖的所有主题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值