第14章 C++中的代码重用
1.包含对象成员的类
包含其他类对象的类,即has-a关系。用于建立has-a关系的C++技术是组合(包含):
class Student
{
private:
typedef std::valarray<double> ArrayDb;
std::string name;
ArrayDb scores;
std::ostream & arr_out(std::ostream & os) const;
public:
Student() : name(“Null Student”), scores(){
}
explicit Student(const std::string & s) : name(s), scores() {
}
explicit Student(int n) : name(“Nully”), scores(n) {
}
Student(const std::string & s, int n) : name(s), scores(n) {
}
Student(const std::string & s, const ArrayDb & a) : name(s), scores(a) {
}
Student(cconst char * str, const double * pd, int n) : name(str), scores(pd, n) {
}
~Student() {
}
double Average() const;
const std::string & Name() const;
double & operator[](int i);
double operator[](int i) const;
friend std::istream & operator>>(std::istream & is, Student & stu);
friend std::istream & getline(std::istream & is, Student & stu);
friend std::ostream & operator<<(std::ostream & os, const Student & stu);
};
使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现)。获得接口是is-a关系的组成部分。而使用组合,类可以获得实现,但不能获得接口。不继承接口是has-a关系的组成部分。
2.私有继承
C++还有另一种实现has-a关系的途径——私有继承。使用私有继承,基类的公有成员和保护成员都将称为派生类的私有成员。
包含将对象作为一个命名的成员对象添加到类中,而私有继承将对象作为一个未被命名的继承对象添加到类中。使用术语子对象来表示通过继承或包含添加的对象。
要进行私有继承,将使用关键字private而不是public来定义类(实际上,private是默认值,因此省略访问限定符也将导致私有继承):
class Student : private std::string, private std::valarray<double>
{
public:
//...
};
使用多个基类的继承被称为多重继承。
包含版本提供了两个被显式命名的对象成员,而私有继承提供了两个无名称的子对象成员。
隐式地继承组件而不是成员对象将影响代码的编写,因为不能使用name和scores来描述对象。新版本的构造函数将使用雷鸣而不是成员名来标识构造函数:
Student(const char * str, const double double * pd, int n) : std::string(str), ArrayDb(pd, n){
}
在私有继承中使用类名和作用域解析运算符来调用基类的方法:
double Student::Average() const
{
if (ArrayDb::Size() > 0)
return ArrayDb::sum() / ArrayDb::size();
else
return 0;
}
在私有继承中,如果要使用基类对象本身,可以利用强制类型转换:
const string & Student::Name() const
{
return (const string &) *this;
}
在私有继承中,如果要使用基类的友元函数,可以通过显式地转换为基类来调用正确的函数:
ostream & operator<<