公有继承是实现代码重用目标的方式之一,同时还有一种方法:使用本身是另外一个类的对象的类成员,简单的说就是一个类的成员包含用另外一个类创建的对象,这种方法被称为包含(containment)、组合(composition)或层次化(layering);还有一种方法是使用私有继承或保护继承,用于实现has-a关系。
一、包含对象成员的类:
1、valarray类
valarry由头文件valarray支持,是一个定义的模板类,用于处理数值,或具有类似性质的类,支持:max()、min()、sun()、size()、operator[]()等一系列操作。
模板类:模板类与类的关系就相当于模板函数与普通函数的关系,将在此之后对如何创建模板类做进一步讲解。
使用模板类: valarray<type>name; //name为定义的名字,type为数据结构。
创建valarray的对象及构造函数的使用:
double gpa[5] = {3.1, 3.5, 3.8, 2.9, 3.3};
valarray<double>v1; //an array of double, include 0 elements;
valarray<int>v2(8); //an array of int, include 8 elements,
valarray<int>v3(10,8); // an array of int, include 8 elements, and each length set to 10
valarray<double>v4(gpa,4); // an array of 4 elements, and initialized to the first
// 4 elements of gpa;
倘若要设计一个student类,类成员为学生名和一系列考试分数,那么学生名可以通过创建一个string对象实现,同时这一些考试分数可以通过创建一个valarray对象实现,这就是 has - a 关系:Student Class has a string object.
接口和实现:
使用公有继承时,类可以继承接口,还可能获得实现(反:基类的纯虚函数提供接口 而不提供实现),这是 is - a 关系的组成部分;然而,使用组合,类可以获得实现,而不能获得接口,不继承接口是 has - a关系的组成部分。
不继承接口具体体现在例如:在string类中,+被重载为字符串的拼接,然而我们并不需要这一接口——将两个字符串拼接并没有意义,因此不继承接口对新的类有利。
explicit 和 约束:
当成员函数的参数类型与提供的参数不匹配时,提供一个用一个参数调用的构造函数将用作从参数类类型的隐式转换函数,然而,在大部分情况这并不是一件好事情,思考以下(注意:在Student类的实现中提供了[]的重载,使得其对象的[]能够访问其包含的vallarray对象的[]相应成员):
Student dol("Homer",10);
dol = 5;
然而,若此时并不是dol[0] = 5,而是直接dol = 5,左边是一个Student类对象,右边是int类型数据,此时将使用将5转换为一个类对象,再通过默认的复制构造函数进行赋值,因此,编译器并不认为其有问题,而在运行时发生错误。而在使用explicit后,编译器将认为以上语句是错误的:explicit使得函数只接受强制的显示转换。这样做的目的在于:在编译阶段出现错误优先于在运行阶段出现错误。
初始化: