第14章 C++中的代码重用
包含、私有继承和保护继承用于实现has-a关系,即新的类将包含另一个类的对象。
多重继承使得能够使用两个或更多的基类派生出新的类,将基类的功能组合在一起。
类模板使我们能够使用通用术语定义类,然后使用模板来创建针对待定类型定义的特殊类。
14.1.1 valarray 类简介
14.2 私有继承
实现has-a关系的另一种途径—私有继承。使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员。
// studenti.h -- defining a Student class using private inheritance
#ifndef STUDENTC_H_
#define STUDENTC_H_
#include <iostream>
#include <valarray>
#include <string>
class Student : private std::string, private std::valarray<double>
{
private:
typedef std::valarray<double> ArrayDb;
// private method for scores output
std::ostream & arr_out(std::ostream & os) const;
public:
Student() : std::string("Null Student"), ArrayDb() {}
explicit Student(const std::string & s)
: std::string(s), ArrayDb() {}
explicit Student(int n) : std::string("Nully"), ArrayDb(n) {}
Student(const std::string & s, int n)
: std::string(s), ArrayDb(n) {}
Student(const std::string & s, const ArrayDb & a)
: std::string(s), ArrayDb(a) {}
Student(const char * str, const double * pd, int n)
: std::string(str), ArrayDb(pd, n) {}
~Student() {}
double Average() const;
double & operator[](int i);
double operator[](int i) const;
const std::string & Name() const;
// friends
// input
friend std::istream & operator>>(std::istream & is,
Student & stu); // 1 word
friend std::istream & getline(std::istream & is,
Student & stu); // 1 line
// output
friend std::ostream & operator<<(std::ostream & os,
const Student & stu);
};
#endif
2)访问基类的方法
使用私有继承时,只能在派生类的方法中使用基类的方法。(在使用包含时将使用对象名来调用方法,而使用私有继承时将使用类名和作用域解析运算符来调用方法。)
14.2.3 保护继承
保护继承在列出基类时使用关键字protected:
14.3 多重继承(MI)
MI描述的是有多个直接基类的类。公有MI表示的也是is-a关系:
class SingingWaiter:public Waiter,public Singer{...};
注意,必须使用关键字public来限定每一个基类。如果缺省关键字,编译器将认为是私有派生。
14.3.1
C++引入多重继承的同时,引入了一种新技术----虚基类(virtual base class),使MI成为可能。
- 虚基类
虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。
例如,通过在类声明中使用关键字virtual,可以使worker被用作singer和waiter的虚基类(virtual和public的次序无关紧要):
class singer:virtual public worker{...};
class waiter:public virtual worker {...};
然后,可以将singingwaiter定义为:
class singingwaiter:public singer,public waiter {...};
- 新的构造函数规则
使用虚基类时,需要对类构造函数采用新的方法。对于非虚基类,唯一可以出现在初始化列表中的构造函数是即时基类构造函数。显式基类构造函数可为:
singingwaiter(const worker & wk,int p=0,int v=singer::other):worker(wk),waiter(wk,p),singer(wk,v){}
对于虚基类,显式地调用构造函数worker(const worker &)是合法的,但对于非虚基类,则是非法的。
在祖先相同时,使用MI必须引入虚基类,并修改构造函数初始化列表的规则。
14.4 类模板
C++的类模板为生成通用的类声明提供了一种更好的方法。
模板提供参数化类型,即能够将类型名作为参数传递给接收方来建立类或函数。
14.4.1 定义类模板
可以将所有的模板信息放在一个头文件中,并在使用这些模板的文件中包含该头文件。
// stacktp.h -- a stack template
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>
class Stack
{
private:
enum {MAX = 10}; // constant specific to class
Type items[MAX]; // holds stack items
int top; // index for top stack item
public:
Stack();
bool isempty();
bool isfull();
bool push(const Type & item); // add item to stack
bool pop(Type & item); // pop top into item
};
template <class Type>
Stack<Type>::Stack()
{
top = 0;
}
template <class Type>
bool Stack<Type>::isempty()
{
return top == 0;
}
template <class Type>
bool Stack<Type>::isfull()
{
return top == MAX;
}
template <class Type>
bool Stack<Type>::push(const Type & item)
{
if (top < MAX)
{
items[top++] = item;
return true;
}
else
return false;
}
template <class Type>
bool Stack<Type>::pop(Type & item)
{
if (top > 0)
{
item = items[--top];
return true;
}
else
return false;
}
#endif
由上述头文件定义可以知道,模板类以下面这样的代码开头:
template <class Type>
14.4.2 使用模板类
stack<int> kernels;
stack<string> colonels;