假如我们现在需要一个Student类,里面储存了学生的name和scores,一般提到name会想到用char数组,提到scores会想到用double型数组,但使用数组就会带来的一个长度不确定的问题,要是声明一个很大的数组,太浪费内存空间,要是在长度不够用的时候再改变长度,则又太繁琐。
这时候可以用C++自带的模板类,用string型变量储存name,用valarray储存scores。
对于valarray,声明语法如下:
valarray<int> v1; //一个int型数组,size为0
valarray<double> v2(8); //一个double型数组,size为8
valarray<int> v3(10,8); //一个int型数组,size为8,每个值都为10
double GPA[4]={3.0,3.6,3.8,4.0,2.9};
valarray<double> v4(GPA,4); //一个double型数组,size为4,取GPA数组的前四项给它赋值
valarray使用动态内存分配数组空间,<typename>声明初始化的数组类型。
声明语法乍看之下很像直接声明数组的语法,但声明数组是v[],这里是v(),它本质上是类的构造函数。
valarray有size,sum,max,min等基本方法可以让使用者了解数组的基本情况。
现在已经有了可以存放的name和scores的模板类,根据刚学的公有继承,一般会想到让Student类同时继承这两个模板类,C++支持这一点,但这里不行。因为公有继承表示的是一种is-a关系,即派生类本质上也是基类(apple是fruit),而这里需要的关系是Student类包含string,valarray类,这被成为has-a关系,具体实现方法为:
class Student{
private:
string name;
valarray<double> scores;
public:
......
};
has-a关系和is-a关系有很大的不同,has-a关系只获得类成员的实现不继承类成员的接口,要想对Student里的string对象name做出修改,需要调用string类的公有接口,例如name.size()调用name的size方法。
下面给出一段较完整的Student类定义:
typedef valarray<double> varrayDB; //valarray<double>可以像int,double一样取别名
class Student{
private:
string name; //这里只是声明,给下面的Student构造函数提供一个可以调用的类成员
varrayDB scores;
public:
Student():name("NULL student"),scores(){} //Student类要通过string和varrayDB调用他们的方法
explicit Student(int n):name("NULL student"),scores(n){} //用explicit关键字修饰只需一个参数的构造函数,避免Student stu=5这种隐式转换
Student(const string& s,int n):name(s),scores(n){}
~Student(){}
};