C++ 之 泛型程序设计与多态
泛型程序设计(Generic Programming)
- 算法实现时不指定具体要操作的数据的类型
- 泛型 \(\Rightarrow\) 算法实现一遍 \(\Rightarrow\) 适用于多种数据结构
- 优势 : 减少重复代码的编写大量编写模板,使用模板的程序设计
函数模板
实现方式 :
template <class 类型参数1, class 类型参数2... ...>
返回值类型 模板名(形参表){
函数体
}
例子 :
template<typename T>
void selectionSort(T arr[], int n){
for(int i = 0 ; i < n ; i ++){
int minIndex = i;
for( int j = i + 1 ; j < n ; j ++ )
if( arr[j] < arr[minIndex] )
minIndex = j;
swap( arr[i] , arr[minIndex] );
}
}
template<class T1,class T2>
T2 print(T1 arg1,T2 arg2){
cout<< arg1<<""<< arg2<<endl;
return arg2;
}
cpp编译器遵循以下优先顺序:
Step 1:先找参数完全匹配的普通函数(非由模板实例化而得的函数)
Step 2:再找参数完全匹配的模板函数
Step 3:再找实参经过自动类型转换后能够匹配的普通函数
Step 4:上面的都找不到,则报错
类模板
- 在定义类的时候给它一个/多个参数
- 这个/些参数表示不同的数据类型
在调用类模板时,指定参数,由编译系统根据参数提供的数据类型自动产生相应的模板类;
类模板定义
template <类型参数表>
class 类模板名{
成员函数和成员变量
}
template <型参数表>
返回值类型 类模板名<类型参数名列表> :: 成员函数名(参数表)
{
... ...
}
用类模板定义对象的写法如下:
类模板名<真实类型参数表>对象名(构造函数实际参数表);
如果类模板有无参构造函数,那么也可以只写:
类模板名<真实类型参数表>对象名;
类模板的参数声明中可以包括非类型参数
template <class T,int elementsNumber>
非类型参数:用来说明类模板中的属性
类型参数:用来说明类模板中的属性类型,成员操作的参数类型和返回值类型
template <class T,int size>
class CArray{
T array[size];
public:
void Print(){
for(int i=0;i<size;++i)
cout << array[i]<<endl;
}
};
类模板与继承
模板类 :即类模板中类型/非类型参数实例化后的类
- 类模板派生出类模板
template <class T1,class T2>
class A{
T1 V1;
T2 v2;
};
template <class T1,class T2>
class B : public A<T2,T1>{
T1 y3;
T2 y4;
};
template <class T>
class C : public B<T,T>{
T v5;
}
- 模板类派生出类模板
template <class T>
class B : public A<int,double>{ T v;};
- 普通类派生出类模板
classA{ intv1;}; template <class T>
class B:publicA{Tv;};
- 模板类派生出普通类
template <class T>
class A{T v1; int n;};
class B : public A<int>{ double v;};
虚函数
- 在类的定义中,前面有
virtual
关键字的成员函数就是虚函数。
class base {
virtual void func(){ }
};
int base::func() {}
- virtual 关键字只用在类定义的函数声明中,写函数体时不用
- 构造函数和静态成员函数不能是许函数
纯虚函数
抽象类:包含纯虚函数的类
- 只能作为基类来派生新类使用
- 不能创建抽象类的对象
- 抽象类的指针和引用 -> 抽象类派生出的类的对象
抽象类中
- 在成员函数中可以调用纯虚函数
- 在构造函数和析构函数中不可以调用纯虚函数
虚析构函数
将基类的析构函数声明为virtual后,可用于实现通过基类指针删除派生类对象时,首先调用派生类析构函数,然后调用基类的析构函数。如果
多态
表现形式一
- 派生类的指针可以赋值给基类指针
- 通过基类指针调用的基类和派生类中的同名虚函数时:
- 若该指针指向一个基类的对象,那么被调用的是基类的虚函数
- 若该指针指向一个派生类的对象,那么被调用的是派生类的虚函数
表现形式二
- 派生类的指针可以赋值给基类引用
- 通过基类引用调用的基类和派生类中的同名虚函数时:
- 若该引用引用的是一个基类的对象,那么被调用的是基类的虚函数
- 若该引用引用的是一个派生类的对象,那么被调用的是派生类的虚函数
用基类指针数组存放指向各种派生类对象的指针,然后遍历该数组,就能对各个派生类对象做各种操作,是很常用的操作。
在非构造函数以及非析构函数的成员函数中调用虚函数就是多态。
多态的原理
多态的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的基类还是派生类的函数运行才确定这叫动态联编
虚函数表
每一个有虚函数的类(或有虚函数类的派生类)都有一个虚函数表,该类的任何对象都放着虚函数表的指针,虚函数表中列出该类的虚函数地址。该虚函数表的地址栈4个字节。
任世事无常,勿忘初心