当我们定义的函数、类的类型是不确定的时候,就需要时候模板技术,在创建的时候显式或隐式的指定参数类型。
定义的方式 :
template
<typename T>
上面的T就是我们要使用的模板类型,下面我们在例子中去学习。
c++中常用的是函数模板、类模板。
函数模板
#include <iostream>
using namespace std;
template
<typename T>
void test(T a) {
T info = a;
cout << info << endl;
}
int main(int argc, char *argv[])
{
test<int>(10);
test(10);
test<float>(3.3);
test(3.3);
return 0;
}
上面就是对函数模板的小例子,注意的是我们的类型可以显式的指定<int>也可以隐式的指定让编译器自己推导,这里推荐显示指定,自己要知道自己想给的类型。
模板分两次编译,第一次编译是对初始模板的类型检查,语法检查等等,第二次是在指定模板类型,调用模板函数的时候展开再一次编译。
最常用的是类模板:
#include <iostream>
using namespace std;
template
<typename T>
class Test {
public:
Test(T a) {
this->a = a;
}
T getA() {
return a;
}
private:
T a;
};
int main(int argc, char *argv[])
{
Test<int>* a = new Test<int>(10);
cout << a->getA() <<endl;
return 0;
}
和函数模板基本相似,值得注意的是在new Test类型的时候需要自己指定类型,和java不同,Java是可以省略自己推导。
模板还可以加入类型变量:
template
<typename T, int N>
#include <iostream>
using namespace std;
template
<typename T, int N>
class Test {
public:
Test(T a) {
this->a = a;
m_length = N;
}
private:
T a;
int m_length;
};
int main(int argc, char *argv[])
{
Test<int, 10>* a = new Test<int, 10>(10);
return 0;
}
这样就可以在定义模板的时候给一个参数进行,一般进行长度信息等的传入。
有的时候我们需要类中的函数是模板的情况,但是类本身不使用模板只需要调用在函数名和()之间加入模板类型:
例子
#include <iostream>
using namespace std;
class Father {
public:
Father() {
}
template
<typename T>
void print(T a) {
cout << a <<endl;
}
};
int main(int argc, char *argv[])
{
Father* a = new Father();
a->print<int>(10);
return 0;
}
还有:
当父类是模板类,并且父类的成员变量是protected,子类要使用父类中的变量的时候必须使用this->指定。
例子:
#include <iostream>
using namespace std;
template
<typename T>
class Father {
public:
Father(T a) {
this->a = a;
}
void print() {
cout << "forward" <<endl;
}
protected:
T a;
};
template
<typename T>
class Son : public Father<T>
{
public:
Son(T a):Father<T>(a)
{
}
T getA() {
this->print();
return this->a;
}
};
int main(int argc, char *argv[])
{
Son<int>* a = new Son<int>(10);
return 0;
}
子类构造函数初始化父类构造函数的时候由于父类也是模板所以需要指定<T>来进行构造,在调用父类的函数以及变量的时候必须this指定,这是因为模板第一次编译的时候就会查找类型定义,然后如果不加this就会当前查找,就没有找到,如果加了this指定,就会看是不是有父类的模板,如果有就会在模板的第二次进行编译。