定义抽象类型的目标:让自定义类型如何内置类型一样易用,其使用符合一般习惯。
确定类接口:当我们准备要编写一个抽象的时候(这里指的是使用类概念),我们首先要确定这个抽象的接口。我们的抽象类型是提供给客户(可能是自己)使用的,那么其接口应该从客户的使用上来考虑。例如,我们准备写一个窗口抽象,那么我们很容易就能够想到,客户可能对这个窗口进行移动、改变大小、显示、隐藏、关闭等等,这些动词就应该列入我们的接口候选列表。
构造、析构、复制和赋值:我们要实例化一个类,就需要对这个类对象进行构造。C++提供了构造函数语义来让我们可以对类对象的构造进行控制。一个类结束其生命周期的时候,我们可能要进行一些处理(比如释放资源等),C++也为我们提供了析构函数语义,让我们在对象生命结束时做一些事情。同样的,对象的复制和赋值等操作也能够在我们的掌握当中,这也得归功于C++提供了复制构造函数语义和重载操作符语义。
默认行为:如果我们不自行编写构造、析构、复制和赋值函数,编译器会为我们生成默认的一些函数,进行一些默认的处理。当然,我们必须得了解C++默认的构造、析构、复制和赋值函数都是如何工作的,以便在其不能满足我们要求的时候我们自行实现。
惯用法:这里提出一个C++惯用法,是关于析构、复制和赋值的。经验得出,析构、复制和赋值这三个行为关系非常密切,所以当C++程序员自行实现了其中某一个的时候,另外两个通常都应该一起实现。
复制和赋值:复制(拷贝构造)和赋值是完全不同的两个概念,但往往很多人容易将二者混淆。复制在这里指的是一种构造语义,是通过另一个已经存在的老对象来构造一个新的对象,新的对象是老对象的一个副本(内部数据值相同)。而赋值不是构造语义,顾名思义,赋值即赋予值的意思,也即使说是给对象赋予新的值,它的前提就是被赋值的对象已经存在。
本章教材以实现一个简化的Vec为例,阐述了如何去定义抽象数据类型。学习这一章,大家应该学会在定义抽象数据类型的时候,不要以实现为导向去设计类,而应该以用户使用为导向结合类本身应该具备的语义去设计。之所以提出这一点,也是我们通过课堂上大家的反馈,发现大家都习惯于在设计时就过多的考虑实现,导致设计出来的抽象不易用,不符合语义等等。
教材中代码: