十一、模板与继承
1、当从模板类派生出子类时必须注意的是:子类并不会从通用的模板基类继承而来,只能从基类的某一实例继承而来。
这样的话就有以下几种继承方式:
a、基类是模板类的一个特定实例版本,比如template<class T> class B : public A<int>{};
b、基类是一个和子类相关的一个实例,比如template<class T> class B : public A<T>{};
这时当实例化一个子类B的时候,基类就相应的被实例化为一个和子类相同的实例版本,比如B<int> m;模板类B被实例化为int 版本,这时基
类A也相应的被实例化为int版本。
c、template<class T> class B : public T 这种用法最普遍,也最难 ,ATL中广泛使用此法.属于基于模板的复用,和基于继承的复用不同.它非常巧妙的用了模板的特性模拟了C++的多态,而不是采用虚函数.
d、如果基类是一个特定的实例的版本,这时子类可以不是一个模板,比如class B : public A<int>{}。
//模板与继承的示例
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
//模板与继承的示例
template<class T>
class A
{
public:
void ga()
{
cout<<"class A "<<typeid(T).name()<<endl;
}
};
//以下是几种继承方式
template<class T1> class B : public A<int>{public: void gb(){cout<<"class B "<<typeid(T1).name()<<endl;}};
template<class T2> class C : public A<T2>{public: void gb(){cout<<"class C "<<typeid(T2).name()<<endl;}};
//template<class T3> class D: public A<T>{} //错误,模板形参T在这里是不可见的说明符。错误原因在于,继承并不会从通用的基类中继承而来,只能是从某一特定的基类中继承而来。
class E: public A<double>{}; //从特定实例继承时子类可以是一般的类
void main()
{
B<double> m;
m.ga(); //输出class A int;
m.gb(); //输出class B double;
C<double> mc;
mc.ga(); //输出class A double
mc.gb(); //输出class C double
}
十二、模板中的关键字typename和class的区别
1、首先typename是一个较新的关键字,而class是比较老的关键字,在类模板的声明中使用哪个都是一样的。
2、必须使用typename 关键字的情况:当有一个模板,且模板的类型形参和某一个类名同名,而且这个同名的类中又有
一个嵌套类的时候就要使用关键字typename了,比如有类class T{public: class A{};}; 则template<class T> class B{T::A
m;};这时的语句就会出错,因为模板类B 无法区别出T::A 表示的是一个类型还是一个数据成员,在C++里面默认情
况下是一个数据成员,在这里的语句T::A m就会出错,会出现m前缺少类型说明符的错误。要使该式正确就必须在
T::A前加上typename关键字以说明T::A表示的是一个类型。即template<class T> class B{typename T::A m;}这样就正
确地声明了一个类T 的嵌套类A 的对象m。当然如果模板的类型形参和那个类名不同名时不会出现这种错误,比如
把嵌套类B的外围类的类名改为D,则在模板类B中的语句D::B m;将是正确的语句。
#include "iostream"
using namespace std;
//关键字typename 和class 的区别的示例
class T
{
public:
static int e;
class B
{
public:
void gb()
{
cout<<"class B"<<endl;
}
};
}; //定义一个带有嵌套的类T。
int T::e = 3;
template<class T1> class A
{
public:
T::B a;
}; //模板形参与带有嵌套的类T不同名,所以这里的语句T::B a是正确的。当然在前面加上
//typename关键字也不会出错。
template<class T>
class D
{
public:
typename T::B b;
}; //模板形参与带有嵌套类的类名同名,在语句T::B b;前必须加上typename以指
//定这里的嵌套类B是一个类型而不是一个表达式。
template<class T>
class F
{
public:
void g()
{
int a = T::e;
cout<<a<<endl;
}
};//这个范例可以看出如果不在T::e前加typename则系统
// 默认表示的是e是一个数据成员,而不是一个类型。
int main()
{
A<int> ma;
ma.a.gb(); //输出class B
D<int> md;
md.b.gb(); //输出class B
F<int> mf;
mf.g();//输出数字3,在这里可以清楚的看到T::e默认表示的是一个数据成员而不是类型。
}