C++进阶教程之类模板
程序员文章站
2022-06-26 15:15:58
...
目录
什么要有模板
记住两句话就够了:
1:类型参数化
2:将与类型无关的底层逻辑抽象出来
对于类模板呢,依然是这两条含义:
1:类型参数化
2:将数据结构的表示与算法不受所包含元素的类型影响、数据结构与算法的分离(数据类型与算法的分离)
比如链表可以存储int char double类型的元素,那么对链表进行排序,则链表的数据结构的表示及其排序算法都可以避免受到包含元素的类型的影响。
注意的几点:
1:模板类是抽象的,必须对其进行参数列表的初始化,这样编译器才知道要分配多少内存。(C++编译器要求具体的类)
而函数模板可以自动的进行类型推导,这是一点不一样的地方。模板类到具体的类再到具体的对象
2:类模板的对象做函数参数:依然需要提前进行参数的初始化
3:类模板中如果自己定义了构造函数,则实例化时也需要对应使用该构造函数,注意类模板是不存在默认构造函数的。
加上参数列表之后,生成了A<double>这个类,而这个类是不存在默认构造函数的,与普通类有较大区别。
模板类的派生(模板类派生普通类)
其实模板类的派生也就是将模板类转化成具体的类之后才能再进行派生(具体化模板类,C++编译器需要知道基类的数据类型是怎样的,因为在定义派生类时需要调用基类的构造函数,也需要提前知道基类所占的数据空间,数据类型确定,才能给派生类分配具体的内存大小)
且,需要在派生类中显示的调用模板基类的构造函数进行自己构造函数的初始化,使用参数的初始化列表。
模板类派生模板类
也必须使用基类的构造函数,初始化列表进行确定。(因为基类的构造函数永远是首先进行调用的)
敲敲代码
#include<iostream>
using namespace std;
template<typename T>
class A {
public:
A(T b)
{
a = b;
}
void printA()
{
cout << "a: " << a << endl;
}
private:
T a;
};
//对应第二条做函数参数应参数初始化
void class_print(A<int> target)
{
}
//派生普通类,需类型初始化
class B : public A<double>
{
public:
//注意基类构造函数需要显式初始化
B(int a, double b) :A(b)
{
c = a;
}
void printA()
{
cout << "c: " << c << endl;
}
private:
int c;
};
//派生模板类
template<typename T>
class C :public A<T>
{
public:
//注意基类构造函数需要显式初始化
C(T a) :A(a)
{
d = a;
}
C(T a,T e) :A(a)
{
d = e;
}
void printA()
{
cout << "d: " << d << endl;
}
private:
T d;
};
int main()
{
A<int> target1(100);
target1.printA();
//错误使用
//A target2(1.25);//对应第一条需要进行参数的初始化
//A<double> target;//对应第三条不存在默认构造函数
B target2(10, 2.25);
target2.printA();
C<char> target3('a','b');
target3.printA();
return 0;
}