模板对象意味着声明对象时,必须指定具体的数据类型。
valarry 类:用于处理数值。主要包含的方法有:
- operator[]() 访问各个元素
- size(), sum(), max(), min()
包含(组合)对象
通常用于has-a关系的C++技术是组合(包含),也就是创建一个包含其他对象的类。(换言之就是在类里面包含了其他类作为成员对象)
虽然私有继承也可以实现 has-a 的关系,但是包含在使用过程中更加简单易于掌握,所有收到大多C++程序员的喜欢。当然私有继承也有自己独特的优势,是包含所无法替代的。
class Student {
private:
string name; // use string object for name
valarray<double> score; // ues valarrya object for scores
};
接口和实现
- 使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现)。获得接口是 is-a 关系的组成部分。
- 使用组合,类可以获得实现,但不能获得接口。不继承接口是 has-a 关系的组成部分。
友元函数(friend 修饰):是一个不属于类成员函数的函数,但是该函数可以访问类的私有成员。通常正确的使用友元函数可以提高运行效率,但是由于可以访问私有成员同时也破坏了类的封装性和数据的隐蔽性。
C++的约束
- explicit 防止单参数构造函数的隐式转换。通常用在但参数构造函数前面进行修饰,可以关闭隐式转换。
- const 限制方法修改数据。
这样做的目的是:在编译阶段出现错误优于在运行阶段出现错误(即将错误前置)。
(1)初始化被包含的对象
- 对于继承的对象,构造函数在成员初始化列表中使用类名调用特定的基类构造函数。
- 对于成员对象,构造函数则使用成员名。
hasDMA::hasDMA(const hasDMA& hs) : baseDMA(hs) {...}
Student(const char* str, const double* pd, int n)
: name(str), score(pd, n) {}
//该构造函数初始化的是成员对象,而不是继承的对象,所以初始化
//列表中使用的是成员名,而不是类名。
//实际中都调用匹配的构造函数,即name(str)调用string(const char*)
C++在构建对象的其他部分之前,会首先构建继承对象的所有成员对象。因此,如果省略初始化列表,将使用成员对象所属类的默认构造函数。
初始化顺序
- 当初始化列表包含多个项目时,初始化的顺序为它们声明的顺序,而不是在初始化列表中的顺序(声明决定初始化优先级)。
const 成员函数:成员函数后面加const代表该成员函数为可读函数,也就是说不可以修改数据成员的值。例如:double Student::Average() const {...}
(2)使用被包含对象的接口
被包含对象的接口不是公有的,但可以在类方法中使用它。(即只能通过类方法使用包含类的接口)