.1 类模板语法
template<class NameType,class AgeType> //包含两个成员属性,所以用两个T
class Person {
public:
NameType m_name;
AgeType m_age;
};
Person<string, int> p; //实例化只能用显示指定类型
.2 类模板与函数模板的区别
- 类模板 没有自动类型推导的使用方式
- 类模板 在模板参数列表中可以有默认参数
template<class NameType,class AgeType=int> //默认参数
class Person {
public:
NameType m_name;
AgeType m_age;
};
Person<string> p; //则实列化时可以去掉一个参数
.3 类模板中成员函数创建时机
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
在编译生成时才会报错(暂时不知道有什么实用价值)
class Person1 {
public:
void showPerson1() {
cout << "Person1的调用" << endl;
}
};
class Person2 {
public:
void showPerson2() {
cout << "Person2的调用" << endl;
}
};
template<class T>
class mYclas {
public:
T obj;
void func1() {
obj.showPerson1();
}
void func2() {
obj.showPerson2();
}
};
int main() {
mYclas<Person1> p;
p.func1();
p.func2(); //
system("pause");
return 0;
}
.4 类模板对象作为函数参数
传入方式有三种:
- 指定传入的类型----直接显示对象的数据类型
template <class T1,class T2>
class Person {
public:
Person(T1 na, T2 a) {
this->name = na;
this->age = a;
}
void showPerson() {
cout << this->name << this->age << endl;
}
T1 name;
T2 age;
};
void printPerson(Person <string, int>& p) { //指定传入类型
cout << "成功传参" << endl;
}
void test1() {
Person <string, int>p("zha", 22);
printPerson(p);
}
- 参数模板化 ----将对象中的参数变为模板进行传递
利用typeid(T1).name()
可知类型
template<class T1, class T2> //需要加上声明
void printPerson(Person <T1,T2>& p) {
cout << "成功传参" << endl;
cout << "T1的类型是:" << typeid(T1).name() << endl;
}
- 整个类模板化 —将这个对象类型模板化进行传递
template<class T> //将Person类看作模板
void printPerson(T& p) {
cout << "成功传参" << endl;
cout << "T的类型是:" << typeid(T).name() << endl;
}
.5 类模板与继承
- 子类继承的父类是一个模板时,子类在声明时,要确定下来父类中T的类型
template<class T1,class T2>
class Person {
public:
T1 name;
T2 age;
};
class Chinese :public Person <string, int> { //需要指出
public:
};
- 若子类仍然想灵活使用父类的T,子类也需要变为类模板
template<class T1,class T2>
class Person {
public:
T1 name;
T2 age;
};
template<class T3, class T4>
class Chinese :public Person <T3,T4> {
public:
//当实例化Chinese时,传参给T3 T4,再传给父类的T1 T2。子类的模板用T1 T2也可以
};
.6 类模板成员函数类外实现
需要声明是类模板类名<模板...>::
template<class T1,class T2>
class Person {
public:
Person(T1 na, T2 a);
void showPerson();
T1 name;
T2 age;
};
//构造函数的类外实现
template<class T1, class T2> //告诉编译器T1 T2未定参数类型
Person<T1,T2>::Person(T1 na, T2 a) {
this->name = na;
this->age = a;
}
//成员函数的类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << this->name << this->age << endl;
}
.7 类模板成员函数分文件编写
第一种方法:直接在包含实现文件.cpp ( 很少使用这种方法)
第二种方法:将声明.h和实现.cpp内容写在一起,后缀改为.hpp文件,来告诉编译器是一个类模板
.8 类模板与友元
全局函数作类内实现
template<class T1,class T2>
class Person {
public:
//全局函数类内实现
friend void Printperson(Person<T1, T2> p) {
cout << this->name << this->age << endl;
}
Person(T1 na, T2 a) {
this->name = na;
this->age = a;
}
private:
T1 name;
T2 age;
};
void test1() {
Person<string, int> p1("zhgang", 12);
Printperson(p1);
}
类外实现较繁琐。需要在类内声明加上<>告诉是一个函数模板,然后要将函数模板写在最上面,还需要声明存在一个类。
//类存在声明
template<class T1, class T2>
class Person;
//函数模板先声明
template<class T1, class T2>
void Printperson(Person<T1, T2> &p) {
cout << p.name << p.age << endl;
}
template<class T1,class T2>
class Person {
public:
Person(T1 na, T2 a) {
this->name = na;
this->age = a;
}
//声明是一个函数模板
friend void Printperson<>(Person<T1, T2> &p);
private:
T1 name;
T2 age;
};
实例运用:创建一个自己的通用数组类
#pragma once
#include <iostream>
using namespace std;
template<class T>
class myArr {
public:
//有参构造
myArr(int capa) {
//cout << "有参构造" << endl;
this->m_capa = capa;
this->m_size = 0;
this->padd = new T[this->m_capa];
}
//拷贝构造
myArr(const myArr& p) {
//cout << "拷贝构造" << endl;
this->m_capa = p.m_capa;
this->m_size = p.m_size;
this->padd = new T[p.m_capa]; //开辟数组空间
//将数据也拷贝过来
for (int i = 0; i < p.m_size; i++) {
this->padd[i] = p.padd[i];
}
}
//重载赋值运算符
myArr& operator=(myArr& p) {
if (this->padd != NULL) {
delete this->padd;
this->m_capa = NULL;
}
this->m_capa = p.m_capa;
this->m_size = p.m_size;
this->padd = new T[p.m_paca]; //开辟数组空间
//将数据也拷贝过来
for (int i = 0; i < p.m_size; i++) {
this->padd[i] = p.padd[i];
}
}
//尾插法
void push_back(const T&va) {
//容量已满无法再插入
if (this->m_capa == this->m_size) {
return ;
}
this->padd[this->m_size] = val;
this->m_size++;
}
//尾删法 逻辑上删除
void pop_back() {
if (this->m_size == 0) {
return 0;
}
this->m_size--;
}
//通过下标访问数组 重载运算符
T& operator[](int index) { //想要作为左值arr[1]=12;需要返回&引用数据类型
return this->padd[index];
}
//析构函数 解决野指针问题
~myArr() {
//cout << "析构" << endl;
if (this->padd != NULL) {
delete this->padd;
this->m_capa = NULL;
}
}
private:
T* padd; //指针指向堆区的数组
int m_capa; //容量即所占存储空间
int m_size; //大小即元素个数
};