类模板的派生和模板类的派生
//下面是我自己总结理解的,还在查找依据当中。
1. 类模板 vs 模板类
类模板是模板的一种, 可以在使用时确定类的类型。
类模板不是一个类,不能直接用于生成对象。 Foo f;是错误的。
template< class T> class Foo { T tVar; //... };
模板类 就是 类模板的一个实例,是一个确定了类型的 具体的类。可以直接生成对象。
Foo<int> 或 Foo<double> 就是两个Foo的模板类。 可以直接生成对象 Foo<int> fi; Foo<double> fd; 都正确。
2.模板类的派生。 此处模板类也称为“非依赖型基类”
模板类就是一个具体的类,和一般的类没有区别,派生时也没有区别。
class Sun : public Foo<int> { //tVal是int } class Sun2: public Foo<double> { //tVal是double }
但,当派生类是一个类模板的时候,有一个问题需要注意。在派生类中的非限定类型的查找,会先查找这个非依赖型基类,然后才会查找模板参数列表。
template<typename T> class Base { public: int basefield; typedef int T; }; template<typename T> class D2:public Base<double> { public: void f() { basefield = 7; }//正常访问继承成员 T strange; //T是Base<double>::T,而不是模板参数 。 };
3.类模板的派生。 --派生类也一定是模板
这种情况下,应注意的问题是:非依赖性名称(即普通成员,跟T类型没关系的)不会在依赖基类中查找 (注,Windows的VC已经让这种方式通过编译了。)
template<typename T> class Base { public: int basefield; }; template<typename T> class D2:public Base<T> { public: void f() { basefield = 7; }//不认识basefield };
解决方法就是将非受限名称改为受限名称。 简单来说就是显示的说明basefield是这个类的成员。
1)this->basefield = 7;
2) Base<T>::basefield =7;
但用这种方式的问题是,如果该成员是个虚函数,则失去了多态的性质。
至于为什么明明是父类的成员 却 在子类中被隐藏了,是因为模板存在特化。特化相当于是另一个类,所以很可能在特化版本中,根本没有这个成员。
为了防止在继承特化版本,调用该成员时报错,就假定不知道 父类中有没有这个成员,所以需要显式说明。 具体可以参看<<Effective C++>>条款43.
路是一步一步走的