14.1 包含对象成员的类
valarray类
has-a关系
学生包含姓名与一组考试成绩
class Student {
private:
string name;
valarray<double> scores;
// ...
}
C++和约束*
如果省略初始化列表,C++将使用成员对象所属类的默认构造函数
初始化顺序
当初始化列表中包含多个项目时,这些项目被初始化的顺序是为他们被声明的顺序,而不是他们在初始化列表中的顺序。
14.2 私有继承
C++还有另一种实现has-a关系的途径——私有继承。使用私有继承,基类的共有成员和保护成员都将成为派生类的私有成员。这意味着基类方法将不会成为派生对象公有接口的一部分,但可以在派生类的成员函数中使用他们。
class Student : private std::string, private std::valarray<double> {
public:
};
使用多个基类的继承被成为多重继承。
1、初始化基类组件
Student(const char * str, const double * pd, int n)
:string(str), ArrayDb(pd, n) {
}
2、访问基类的方法
使用私有继承时,只能在派生类的方法中使用基类的方法。
可以在公有Student::average()函数中使用私有的Student::Average()函数。包含使用对象来调用方法
私有继承使得能够使用类名和作用域解析运算符来调用基类的方法
3、访问基类对象
使用强制类型转换
const string & Student::Name() const {
return (const string &) *this;
}
4、访问基类的友元函数
os << "Scores for " << (const String &) stu << ":\n";
通常,应使用包含来建立has-a关系;如果新类需要访问原有类的保护成员,或需要重新定义虚函数,则应使用私有继承
保护继承
保护继承时私有继承的变体。保护继承在列出基类时使用关键字protected:
class Student : protected std::string,
protected std::valarray<double>
使用保护继承时, 基类的公有成员都将成为派生类的保护成员。和私有继承一样,基类的接口在派生类中也是可用的,但在继承层次在结构之外是不可用的。
但,当从派生类派生出另一个类时,便有了区别。私有继承时,第三代类将不能使用基类的接口,这是因为基类的共有方法在派生类中变成了私有方法;使用保护继承时,基类的公有方法在第二代中将变成受保护的,因此第三代派生类中可以使用他们。
使用using 重新定义访问权限
假设要基类的方法在派生类外面可用,方法之一是定义一个使用该基类方法的派生类方法。
另一种方法是使用using
public:
using std::valarray<double>::min;
using std::valarray<double>::max;
注意:using声明只使用成员名——没有圆括号、函数特征标和返回类型。
14.3 多重继承
共有MI表示的是is-a关系
私有MI和保护MI可以表示has-a关系
MI的两个主要问题:从两个不同的基类中继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例。
因为Singer和Waiter都继承了一个Worker组件,因此SingerWaiter将包含两个Worker组件。
将派生类对象的地址赋给基类指针时,将出现二义性,应使用强制类型转换来指定对象。
Worker * pw1 = (Waiter *) &ed;
Worker * pw2 = (Singer *) &ed;
但,实际上,只需要一个Worker
引入新技术:虚基类
虚基类
虚基类使得从多个类派生出的对象只继承一个基类对象。
class Singer