通常保护和私有继承用于实现has-a关系
公有继承实现is-a关系
抽象基类是为了抽象出类之间的相同部分
类模板和函数模板是为了实现代码重用
使用explicit防止单参数构造函数的隐式转换。使用const限制修改数据。
根本原因:在编译阶段出现的错误优于在运行阶段出现的错误。
数据成员被初始化的顺序取决于声明的顺序而不是初始化列表的顺序
私有继承
私有继承只能使用一个类对象
私有继承派生类可以重新定义虚函数。
私有继承,基类的公有成员和保护成员都会变成派生类的私有成员
保护继承,基类的公有成员和保护成员都会变成派生类的保护成员
隐式向上转换:无需进行显式类型转换就可以将基类指针或引用指向派生类对象。
私有继承中,访问基类的方法只能通过基类名::方法名访问基类的方法,但是可以使用using 类名::方法名,并将其放在pulic下,将该方法可以在外部使用。像派生类的公有方法一样。
含有纯虚函数的类叫做抽象基类。
虚基类
通过在类声明中使用virtual使继承的类声明为虚基类。
class Singer:virtual public worker{};
class Waiter:public virtual worker{};
对于虚基类,禁止信息通过中间类自动传递给基类,需要显示的调用虚基类的构造函数。如果不提供,将会调用默认的虚基类的默认构造函数。
多重继承导致函数调用的二义性。
不希望外部访问,但是派生类可以访问采用保护继承。
在多重继承时,如果多个基类的祖先相同,则祖先类要使用虚基类,需要修改派生类的构造函数。
泛型:独立于类型
使用typedef缺点:
每次使用一种类型都要重新编译头文件
每次只能使用一种类型
模板类
模板类和模板函数:将参数传递给类或者函数
class C:public A, public B
C.A::fool()
C.B::fool()
模板类的类声明中定义了方法,则可以省略模板前缀和类限定符。
模板成员函数不是类成员函数的定义,不能放在独立的实现文件中。===将模板信息放在一个同文件中。
Stack kernels;
编译器根据Stack模板生成类声明和类方法。
Type是类型变量:接受的值只能是类型,叫做泛型标识符。
template <class T, int n>
n称为非类型或表达式参数
1. 表达式参数类型:整型,枚举,引用或指针。
2. 不能修改表达式参数的值,也不能使用表达式参数的地址。
3. 实例化模板时,表达式参数的值必须是常量表达式。
* 使用不同的表达式参数,将生成不同的自己的模版。n值不同,生成的类声明不同。
模板类可以被继承,也可以将模板类对象作为另一个类的数据成员
模板可以递归使用
使用多个模板参数:template
类模板和函数模板可以有隐式实例化,显式实例化,显式具体化
- 隐式实例化:在创建类实例的时候,指明类型,编译器根据指明的类型生成具体的类定义
- 显示实例化:
template class ArrayTP<string, 100>
显示说明我要生成具体的类定义。 - 具体实例化:为了特殊类型定义的模板类,具体模板和通用模板匹配时,使用具体模板。
//通用模板类:
template <class T>
class SortedArray {
...
};
// 具体模板类:
template <> class SortedArray<const char *> {
...
};
//部分具体化:
template <class T1> class SortedArray <T1, int>{
...
};
在类中可以声明模板类,将类的数据成员声明为模板类对象。
将模板用作模板的参数:
template <template<typename T>class Thing>
模板类的友元函数:
- 非模板友元函数
为什么模板不是类声明却可以有友元?因为模板类不是类声明,而友元函数不属于类,是自己独立存在的。
也是此时的友元函数不能有模板类对象作为参数。除非是具体化类。
错误:friend void report(HadFriend &)
正确:friend void report(HadFriedn<T> &)
指明T可以,在友元函数的定义中必须要指明T的类型才可以。
void report(HadFriedn<int> &)
所有的类实例都会有类型的友元函数 - 约束模板友元函数
所有的类实例有自己类型的友元函数
1)类定义之前声明模板函数:
template <typename T> void counts();
template <typename T> void reports(T &);
2)在类模板中将函数声明为友元
template <typename TT>
class HasFriend{
friend void counts<TT>();
friend void report<>(HasFriend<TT> &)
}
某一个类的友元
此时友元函数的参数列表和类中声明的相同,但是没有函数名后的<>
调用的时候report根据传递的类对象决定TT类型。counts调用:counts()/counts() - 非约束的模板友元函数
模板友元函数的类型参数与模板类类型参数不同。
在模板类中定义:
template <typename C, tepename D> friend void show(C &, D &);
友元函数实现的时候不需要指定friend
模板别名:
typedef int int32
using int32 = int;
typedef std::array(int, 12) arri;
using arri = std::array(int, 12);
template <typename T>
using arrtype = std::array(T, 12);
arrtype<int> days;
virtual不能用在类声明以外
static类成员函数的定义放在类外时,不能使用static
friend友元函数的定义不能使用friend。