1.类模板成员函数类外实现
#include <iostream>
#include <string>
using namespace std;
//类模板成员函数类外实现
template<class T1,class T2>
class Person{
public:
Person(T1 name,T2 age);
//类内实现
// {
// this->m_Name=name;
// this->m_Age=age;
// }
void showPerson();
//类内实现
// {
// cout<<this->m_Name<<this->m_Age<<endl;
// }
T1 m_Name;
T2 m_Age;
};
//构造函数的类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){
this->m_Name=name;
this->m_Age=age;
}
//成员函数的类外实现
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",18);
P.showPerson();
}
int main(){
test01();
}
2.类模板分文件编写
问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:1.直接包含.cpp源文件;2.将声明和实现写在同一个文件中,并更改后缀为.hpp hpp是约定的名称,并不是强制
原因:类模板中成员函数开始的时候是没有创建的
3.类模板与友元
全局函数类内实现-直接在类内声明友元即可
全局函数类外实现-需要提前让编译器知道全局函数的存在
#include <iostream>
#include <string>
using namespace std;
template<class T1,class T2>
//提前让编译器知道Person类的存在
class Person;
//类外实现,提前让编译器知道它的存在
template<class T1,class T2>
void printPerson2(Person<T1,T2> p){
cout<<p.m_Name<<p.m_Age<<endl;
}
//通过全局函数打印信息
template<class T1,class T2>
class Person{
public:
//全局函数类内实现
friend void printPerson(Person<T1,T2> p){
cout<<p.m_Name<<p.m_Age<<endl;
}
//全局函数类外实现
//加一个空模板参数列表
//如果全局函数是类外实现,需要让编译器提前知道它的存在
friend void printPerson2<>(Person<T1,T2> p);
Person(T1 name,T2 age){
this->m_Name=name;
this->m_Age=age;
}
private:
T1 m_Name;
T2 m_Age;
};
void test01(){
Person<string,int>P("Tom",30);
printPerson2(P);
}
int main(){
test01();
}
4.类模板案例 实现通用的数组类
注意!!
有参构造、拷贝构造(注意深浅拷贝的问题!这里的区别在代码里已经有所体现)、
=运算符重载(同样注意深浅拷贝的问题,以及函数调用想作为左值存在,返回该类型的引用)
尾插法的实现、下标访问的实现、析构函数
#include <iostream>
#include <string>
using namespace std;
template<class T>
class MyArray{
public:
//有参构造 参数 容量
MyArray(int capacity){
//cout<<"有参构造调用"<<endl;
this->m_Capacity=capacity;
this->m_Size=0;
this->pAddress=new T[this->m_Capacity];
}
//拷贝构造
MyArray(const MyArray& arr){
//cout<<"拷贝构造调用"<<endl;
this->m_Capacity=arr.m_Capacity;
this->m_Size=arr.m_Size;
//this->pAddress=arr.pAddress;浅拷贝
this->pAddress=new T[arr.m_Capacity];//深拷贝
//将arr中的数据都拷贝过来
for(int i=0;i<this->m_Size;i++){
this->pAddress[i]=arr.pAddress[i];
}
}
//operator= 防止浅拷贝问题
//函数调用想作为左值存在,返回该类型的引用
MyArray& operator=(const MyArray& arr){
//cout<<"operator=调用"<<endl;
//先判断原来堆区是否有数据,如果有先释放
if(this->pAddress!=NULL){
delete[]this->pAddress;
this->pAddress=NULL;
this->m_Capacity=0;
this->m_Size=0;
}
//深拷贝
this->m_Capacity=arr.m_Capacity;
this->m_Size=arr.m_Size;
this->pAddress=new T[arr.m_Capacity];
for(int i=0;i<this->m_Size;i++){
this->pAddress[i]=arr.pAddress[i];
}
return *this;
}
//尾插法
void Push_Back(const T &val){
//判断容量是否等于大小
if(this->m_Capacity==this->m_Size)
return;
this->pAddress[this->m_Size]=val;//在数组末尾插入数据
this->m_Size++;//更新数组大小
}
//尾删法
void Pop_Back(){
//让用户访问不到最后一个元素,逻辑删除
if(this->m_Size==0)
return;
this->m_Size--;
}
//通过下标方式访问数组中的元素
//函数调用想作为左值存在,返回该类型的引用
T& operator[](int index){
return this->pAddress[index];
}
//返回数组容量
int getCapacity(){
return this->m_Capacity;
}
//返回数组大小
int getSize(){
return this->m_Size;
}
//析构函数
~MyArray(){
if(this->pAddress!=NULL){
//cout<<"析构函数调用"<<endl;
delete[]this->pAddress;
this->pAddress=NULL;
}
}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组容量
int m_Size;//数组大小
};
void print(MyArray<int>&arr){
for(int i=0;i<arr.getSize();i++){
cout<<arr[i]<<" ";
}
}
void test01(){
MyArray<int>arr1(5);
for(int i=0;i<5;i++){
arr1.Push_Back(i);
}
print(arr1);
arr1.Pop_Back();
cout<<arr1.getCapacity()<<arr1.getSize()<<endl;
// MyArray<int>arr2(arr1);
// MyArray<int>arr3(100);
// arr3=arr1;
}
//测试自定义数据类型
class Person{
public:
Person(string name,int age){
this->m_Name=name;
this->m_Age=age;
}
string m_Name;
int m_Age;
};
void PrintPerson(MyArray<Person>& arr){
for(int i=0;i<arr.getSize();i++){
cout<<arr[i].m_Name<<" "<<arr[i].m_Age;
}
}
void test02(){
MyArray<Person>arr2(10);
Person p1("孙悟空",999);
Person p2("韩信",33);
Person p3("妲己",20);
Person p4("赵云",15);
Person p5("安其拉",9);
arr2.Push_Back(p1);
arr2.Push_Back(p2);
arr2.Push_Back(p3);
arr2.Push_Back(p4);
arr2.Push_Back(p5);
PrintPerson(arr2);
}
int main(){
test02();
}