类模板作用:建立一个通用类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表。
语法:
template < typename T>
类
解释:
template-----声明创建模板。
typename-----表明其后面的符号是一种数据类型,可以用class代替。
T-----通用的数据类型,名称可以替换,通常为大写字母。
类模板与函数模板的区别主要有两点:
1、类模板没有没有自动类型推导的使用方式,只能用显示指定类型
2、类模板在模板参数列表中可以有默认参数
示例:
#include
#include
using namespace std;
template <class name_type,class age_type = int>//区别2指定为int类型,函数模板没有
class Person
{
public:
Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
void Show()
{
cout << "name:" << this->m_name << " age: " << this->m_age << endl;
}
name_type m_name;
age_type m_age;
};
void test01()
{
// Person<> p1("张三", 18);区别1
Person<string,int> p1("张三",18);//必须使用显示指定类型的方式,使用类模板
p1.Show();
}
void test02()
{
Person<string> p2("李四", 20);//区别2,类模板中的模板参数列表,可以指定默认参数
p2.Show();
}
int main(void)
{
test01();
test02();
return 0;
}
总结:类模板和函数模板非常相似,在声明模板template后面加类,此类称为类模板。
#include
#include
using namespace std;
class Person1
{
public:
void show1()
{
cout << "Person1类中成员函数的调用" << endl;
}
};
class Person2
{
public:
void show2()
{
cout << "Person2类中成员函数的调用" << endl;
}
};
template <class T>
class Myclass
{
public:
T obj;
//类模板中的成员函数并不是一开始就创建的,而是在模板调用时再生成
void func1() {obj.show1(); }
void func2() {obj.show2(); }
};
void test01()
{
Myclass<Person1>m;
m.func1();
// m.func2();//编译会出错,说明函数调用时才会去创建成员函数
}
int main(void)
{
test01();
return 0;
}
总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建。
一共有三种传入方式:
1、指定传入的类型-----直接显示对象的数据类型(常用)
2、参数模板化-----将对象中的参数变为模板进行传递
3、整个类模板化-----将这个对象类型模板化进行传递
补充知识点:
如何查看变量或对象的数据类型
语法:typeid(变量或对象).name()
include <iostream>
#include
using namespace std;
template <class type_name,class type_age>
class Person
{
public:
Person(type_name name, type_age age)
{
this->m_name = name;
this->m_age = age;
}
void showprint()
{
cout << "name: " << this->m_name << " age: " << this->m_age << endl;
}
type_name m_name;
type_age m_age;
};
void printPerson1(Person<string,int>&p)//指定传入的类型
{
p.showprint();
}
template <class T1,class T2>//参数模板化
void printPerson2(Person<T1, T2>& p)
{
p.showprint();
cout << "T1的数据类型为: " << typeid(T1).name() << endl;//查看T1的数据类型
cout << "T2的数据类型为: " << typeid(T2).name() << endl;
}
template <class T>//整个类模板化
void printPerson3(T & p3)
{
cout << "T的类型为: " << typeid(T).name() << endl;//查看T的数据类型
p3.showPerson();
}
void test01()
{
Person <string, int>p1("张三", 18);
printPerson1(p1);
Person <string, int>p2("李四",19);
printPerson2(p2);
Person <string, int>p3("王五",20);
printPerson2(p3);
}
int main(void)
{
test01();
return 0;
}
总结:
1、通过类模板创建的对象,可以有三种方式向函数中进行传参。
2、使用比较广泛是第一种:指定传入的类型。
include <iostream>
#include
using namespace std;
template <class T>
class Base
{
public:
Base() {
cout << "T的数据类型为: " << typeid(T).name() << endl;//int
}
};
//class son : public Base//事项1:必须要指定出父类T的数据类型
class son1 : public Base<int>{};
template <class T1,class T2>//事项2:想灵活指出父类中T的类型,子类也需变为类模板
class son2 : public Base<T1>
{
public:
son2(){
cout << "T1的数据类型为: " << typeid(T1).name() << endl;//int
cout << "T2的数据类型为: " << typeid(T2).name() << endl;//char
}
};
void test()
{
son1 p1;
son2<int, char>p2;
}
int main(void)
{
test();
return 0;
}
总结:如果父类是类模板,子类需要指定出父类中T的数据类型。
#include
#include
using namespace std;
template <class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age);//类内构造函数的声明
void func();//类内成员函数的声明
string m_name;
int m_age;
};
//构造函数类外实现
template <class T1, class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
this->m_age = age;
this->m_name = name;
cout << "Person类构造函数的调用" << endl;
}
//成员函数类外实现
template <class T1, class T2>
void Person<T1, T2>::func()
{
cout << "姓名: " << this->m_name << endl;
cout << "年龄: " << this->m_age << endl;
}
void test()
{
Person<string,int>p1("Tom", 18);
p1.func();
}
int main(void)
{
test();
return 0;
}
//#include "person.h"
#include "person.cpp"//方式1
#include "person.hpp"//方式2
void test()
{
Person<string,int>p1("Tom", 18);
p1.func();
}
int main(void)
{
test();
return 0;
}
方式2:将声明和实现写在一个文件.hpp中。
#include
#include
using namespace std;
template <class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);//类内构造函数的声明
void func();//类内成员函数的声明
T1 m_name;
T2 m_age;
};
//以下为实现部分(或将以下部分写在另一个.cpp文件中,并只包含.cpp文件即可)
//构造函数类外实现
template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_age = age;
this->m_name = name;
cout << "Person类构造函数的调用" << endl;
}
//成员函数类外实现
template <class T1, class T2>
void Person<T1, T2>::func()
{
cout << "姓名: " << this->m_name << endl;
cout << "年龄: " << this->m_age << endl;
}
总结:推荐的解决方式是第二种,将类模板函数写在一起,并将后缀名改为.hpp。
#include
#include
using namespace std;
template <class T1, class T2>
class Person;//用到person这个数据类型,要提前声明
template <class T1, class T2>
void showprint2(Person<T1, T2>& p)//函数定义要写在类前面,提前让编译器知道
{
cout << "姓名为: " << p.m_name << endl;
cout << "年龄为: " << p.m_age << endl;
}
template <class T1,class T2>
class Person
{
friend void showprint2<>(Person<T1, T2>& p);
friend void showprint1(Person<T1, T2>& p) {//全局函数配合友元类内实现
cout << "姓名为: " << p.m_name << endl;
cout << "年龄为: " << p.m_age << endl;
}
public:
Person(T1 age, T2 name) {
this->m_age = age;
this->m_name = name;
}
private:
T1 m_age;
T2 m_name;
};
void test()
{
Person<string, int>p1("Tom", 18);
showprint1(p1);
Person<string, int>p2("Jerry", 16);
showprint1(p2);
}
int main(void)
{
test();
return 0;
}
总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别。