建立一个通用的类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
template<typename T>
类
template: 是声明创建模板
tupename: 后跟数据类型,可以用class代替
T : 通用的数据类型,名称可以替换。
#include
#include
using namespace std;
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name,AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
void showPerson()
{
cout<<"name: "<<this->m_Name << " age: "<<this->m_Age<<endl;
}
};
void test01()
{
Person<string,int> p1("孙悟空",999);
p1.showPerson();
}
int main()
{
test01();
return 0;
}
1.类模板没有自动类型推导的使用方式,必须指明类型。
如: Person p("孙悟空",100); 错误
Person<string,int>p("孙悟空",100); 正确
2.类模板在模板参数列表中可以有默认参数。
1.普通类中的成员函数一开始就创建了
2.类模板中的成员函数在调用时才创建
#include
#include
using namespace std;
template<class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
T1 m_Name;
T2 m_Age;
void showPerson()
{
cout<<"姓名: "<<this->m_Name<<" 年龄: "<<this->m_Age<<endl;
}
};
// 1.类模板对象做函数参数的传递方法一:指定传入类型
void printPerson1(Person<string,int>&p)
{
p.showPerson();
}
void test01()
{
Person<string,int>p("孙悟空",100);
printPerson1(p);
}
// 2.类模板对象做函数参数的传递方法二:把参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p)
{
p.showPerson();
cout<<"T1 的类型为: "<<typeid(T1).name()<<endl;
cout<<"T2 的类型为: "<<typeid(T2).name()<<endl;
}
void test02()
{
Person<string,int>p("猪八戒",90);
printPerson2(p);
}
// 3.类模板对象做函数参数的传递方法三:整个类模板化
template<class T>
void printPerson3(T &p)
{
p.showPerson();
cout<<"T的数据类型为: "<<typeid(T).name()<<endl;
}
void test03()
{
Person<string,int>p("唐僧",30);
printPerson3(p);
}
int main()
{
// 1.类模板对象做函数参数的传递方法一:指定传入类型
// test01();
// 2.类模板对象做函数参数的传递方法一:把参数模板化
// test02();
// 3.类模板对象做函数参数的传递方法三:整个类模板化
test03();
return 0;
}
#include
using namespace std;
// 类模板与继承
template<class T>
class Base
{
T m;
};
// 如果不指定父类的数据类型,那么子类无法分配内存空间,就无法继承。
class Son: public Base<int>
{
};
void test01()
{
Son s1;
}
缺点:子类指定了数据类型,这个数据类型就不能变了。
如果想灵活指定父类中的T类型,子类也需要变类模板
// 二.如果想灵活指定父类中的T类型,子类也需要变类模板
template<class T1,class T2>
class Son2:public Base<T2>
{
public:
Son2()
{
cout<<"T1的类型为:"<<typeid(T1).name()<<endl;
}
T1 obj;
};
void test02()
{
Son2<int,char>S2;
}
测试代码:
int main()
{
test02();
return 0;
}
1.类外实现模板类的构造函数
模板定义
模板类作用域作用域:: 构造函数名
2.类外实现模板类的普通函数
模板定义
函数返回值 模板类作用域:: 普通函数名
案例:
#include
using namespace std;
template<class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age);
void showPerson();
T1 m_Name;
T2 m_Age;
};
// 1.构造函数类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
// 2.成员函数类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson()
{
cout<<"姓名: "<<this->m_Name<<"年龄: "<<this->m_Age<<endl;
}
void test01()
{
Person<string,int> P("Tom",20);
P.showPerson();
}
int main()
{
test01();
return 0;
}
类模板成员函数的创建时机是在调用阶段,导致分文件编写时链接不到。
因为类模板成员函数一开始是不会创建的,当你去包含.h的时候,相当于只是让编译器看到了如下声明的代码。编译器没有看到实现构造函数和 void showPerson()的代码。所以链接阶段失败。
解决方法
1:直接包含.cpp源文件
2.将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称。
把 .h改为.cpp时,相当于让编译器看到了如下实现的代码:
此时编译器可以成功编译了。
但是一般不用这种方法,因为一般是不会直接导入cpp源码的。