01 类模板语法

02 类模板和函数模板的区别

03 类模板中成员函数调用时机

04 类模板对象做函数参数

05 类模板与继承

06 类模板成员函数类外实现

07 模板分类文件编写

08 类模板与友元

09 类模板案例-数组类封装

01 类模板语法

#include<iostream>
using namespace std;

//类模板
template <class NameType, class AgeType>
class Person {
public:
	Person(NameType name, AgeType age)
	{
		this->m_age = age;
		this->m_name = name;
	}
	void print()
	{
		cout << this->m_name<<"  " << this->m_age << endl;
	}

	NameType m_name;
	AgeType m_age;

};

void test1()
{
	Person <string, int> p("永生", 998);
	p.print();
}
int main()
{
	test1();
	system("pause");
	return 0;
}

//类模板和函数模板语法相似,在声明模板template后加类,此类称为.类模板

 02 类模板和函数模板的区别

#include<iostream>
using namespace std;

//类模板
template <class NameType, class AgeType = int>
class Person {
public:
	Person(NameType name, AgeType age)
	{
		this->m_age = age;
		this->m_name = name;
	}
	void print()
	{
		cout << this->m_name << "  " << this->m_age << endl;
	}

	NameType m_name;
	AgeType m_age;

};

//1.类模板没有自动类型推导使用方式
void test1()
{
	//Person  p("永生", 998); //错误,无法用自动类型推导
	Person <string, int> p("永生", 998); //正确,只能用显示指定类型
	p.print();
}

//2. 类模板在模板参数类别可以有默认参数
//上面class AgeType = int可以直接写Person <string>,省略int
void test2()
{
	Person <string> p("永", 1000); 
	p.print();
}

int main()
{
	//test1();
	test2();
	system("pause");
	return 0;
}

//总结
//类模板使用只能用显示指定类型方式
//类模板中的模板参数列表可以有默认参数

03 类模板中成员函数调用时机

#include<iostream>
using namespace std;
class Person1 {
public:
	void showPerson1()
	{
		cout << "person1" << endl;
	}

};


class Person2 {
public:
	void showPerson2()
	{
		cout << "person2" << endl;
	}


};

template<class T>
class Myclass
{
public:
	T obj;
	//类模板中的成员函数,并不是一开就创建的,而是在模板调用时再生成
	void func1()
	{
		obj.showPerson1();
	}
	void func2()
	{
		obj.showPerson2();
	}

};

void test01()
{
	Myclass<Person1>p;
	p.func1();
	//p.func2(); //编译会出错,说明函数调用才会去创建函数
}

int main()
{
	test01();

	system("pause");
	return 0;
}

04 类模板对象做函数参数

#include<iostream>
using namespace std;
//类模板对象做函数参数
template <class T1, class T2>
class Person
{
public:
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showinfo()
	{
		cout << this->m_name << " " << this->m_age << endl;
	}

	T1 m_name;
	T2 m_age;

};

//1.指定传入类型
void printpeson(Person <string, int>&p)
{
	p.showinfo();
}
template <class T1, class T2>

//2.参数模板化
void printpeson2(Person <T1, T2>& p)
{
	p.showinfo();
	cout << "T1类型为" << typeid(T1).name() << endl;
	cout << "T2类型为" << typeid(T2).name() << endl;

}

//3.整个类模板化
template <class T>
void printpeson3(T &p)
{
	p.showinfo();
	cout << "T类型为" << typeid(T).name() << endl;
}

void test1()
{
	Person <string, int>p("孙悟空", 999);
	printpeson(p);
}


void test2()
{
	Person <string, int>p("猪八戒", 934);
	printpeson2(p);
}
void test3()
{
	Person <string, int>p("唐生", 436);
	printpeson3(p);
}

int main()
{
	test1();
	test2();
	test3();
	system("pause");
	return 0;
}
//总结
//通过类模板创建对象,可以有三种方式向函数中进行传参
//使用比较广泛的第一种:指定传入的类型

05 类模板与继承

#include<iostream>
using namespace std;

template <class T>
class Base
{
	T obj;

};

//class Son :Base //错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Base<int>
{

};

//如果想灵活指定父类中T类型,子类也需要变类模板
template <class T1, class T2>
class Son2 :public Base<T2>
{
public:
	Son2()
	{
		cout << "T1的类型" << typeid(T1).name() << endl;
		cout << "T2的类型" << typeid(T2).name() << endl;

	}
	T2 obj;

};

void test1()
{
	Son2 <string, int>p;

}




int main()
{
	test1();
	
	system("pause");
	return 0;
}

 06 类模板成员函数类外实现

#include <iostream>
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 << endl;
		cout << 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 test1()
{
	Person<string, int> p("悟空", 9897);
	p.showPerson();

}
int main()
{
	test1();
	system("pause");
	return 0;
}
//总结类模板中成员函数类外实现时,要加上模板参数列表

07 模板分类文件编写

07 模板分类文件编写

#include <iostream>
using namespace std;
//第一种方式,直接包含源文件
//#include"Person.cpp"
//第二种方式,将.h和.cpp的内容写到一起,将后缀名改为.hpp文件
#include"Person.hpp"
void test1()
{
	Person<string, int> p("悟空", 897);
	p.showPerson();

}
int main()
{
	test1();
	system("pause");
	return 0;
}

 

Person.hpp

#pragma once

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 << endl;
		cout << 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;
}

 

08 类模板与友元

#include<iostream>
using namespace std;
//通过全局函数 打印Person信息
//提取让编译器知道Person类存在
template <class T1, class T2>
class Person;
//类外实现的内容
template <class T1, class T2>

void showPerson2(Person<T1, T2> p)
{
	cout << p.m_name << "," << p.m_age << endl;
}

template <class T1, class T2> 

class Person {
	//全局函数,类内实现
	friend void showPerson(Person<T1, T2> p)
	{
		cout << p.m_name << ","<<p.m_age << endl;
	}
	//全局函数 类外实现
	//加空模板参数列表
	//如果全局函数 是类外实现, 需要让编辑器提前知道这个函数的存在
	friend void showPerson2<>(Person<T1, T2> p);

public:
	Person(T1 name, T2 age)
	{
		this->m_name = name;
		this->m_age = age;
	}
private:
	T1 m_name;
	T2 m_age;

};

//1.全局函数类内实现内容

void test01()
{
	Person<string, int>p("哈哈", 34);
	showPerson(p);
}
//2.全局函数在类外实现
void test02()
{
	Person<string, int>p("嘿嘿", 34);
	showPerson2(p);
}

int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

//总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别

09 类模板案例-数组类封装

#include<iostream>
using namespace std;
#include"myArray.hpp"

void printIntArray(MyArray <int>& arr )
{
	for (int i = 0; i < arr.getm_Size(); i++)
	{
		cout << arr[i] << endl;
	}
	

}

void test01()
{
	MyArray <int>arr1(5);
	for (int i = 0; i < 5; i++)
	{
		arr1.Push_Back(i);
	}
	/*MyArray <int>arr2(arr1);
	MyArray <int>arr3(100);
	arr3 = arr1;*/
	

	printIntArray(arr1);
	
	cout << "arr的容量为" << arr1.getm_Capacity() << endl;
	cout << "arr的大小为" << arr1.getm_Size() << endl;

	MyArray <int>arr2(arr1);

	printIntArray(arr2);
	//尾删
	arr2.Pop_Back();
	
	cout << "尾删后容量" << arr2.getm_Capacity() << endl;
	cout << "尾删后的大小" << arr2.getm_Size() << endl;

}


class Person
{
public:
	Person() {};
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	string m_name;
	int m_age;
};

//测试自定义类型
void Print_Person(MyArray <Person>& arr)
{
	for (int i = 0; i < arr.getm_Size(); i++)
	{
		cout << "姓名" << arr[i].m_name << ""<<endl;
		cout << "年龄" << arr[i].m_age << "" << endl;


	}
}

void test02()
{
	MyArray<Person> arr(10);
	Person p1("物价", 22);
	Person p2("张三", 30);
	Person p3("李四", 10);
	Person p4("王五", 40);
	Person p5("杨六", 50);
	//将数据插入到数组中
	arr.Push_Back(p1);
	arr.Push_Back(p2);
	arr.Push_Back(p3);
	arr.Push_Back(p4);
	arr.Push_Back(p5);
	Print_Person(arr);
}

int main()
{
	test01();
	test02();
	system("pause");
	return 0;
}

 

#pragma once
#include<iostream>
using namespace std;

template <class T>
class MyArray
{
public:
	//有参构造 参数 容量
	MyArray(int capacity)
	{
		//cout << "有参构造" << endl;
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAdress = new T [this->m_Capacity];
	}

	//拷贝构造
	MyArray(const MyArray&arr)
	{
		//cout << "拷贝函数" << endl;

		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAdress = pAdress; //不能这样写,浅拷贝导致堆区数据重复释放
		this->pAdress = new T[arr.m_Capacity]; //深拷贝,用指针维护着他
		//将arr中数据拷贝过来
		for (int i=0; i < this->m_Size; i++)
		{
			this->pAdress[i] = arr.pAdress[i];
		}
	}

	//重载=操作符operator=防止浅拷贝问题
	MyArray& operator=(const MyArray& arr)
	{
		//cout << "operator=调用" << endl;

		//先判断堆区是否有数据,如果有先释放
		if (this->pAdress != NULL)
		{
			delete[] this->pAdress;
			//this->pAdress = NULL;	//防止野指针
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
		//深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAdress = new T[this->m_Capacity];
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAdress[i] = arr[i];
		}
		return *this;
	}

	T& operator [](int index)
	{
		return this->pAdress[index];
	}

	//尾插法
	void Push_Back(const T & val)
	{
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAdress[this->m_Size] = val;
		this->m_Size++;
	}

	//尾删法
	void Pop_Back()
	{
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}
	
	//获取数组容量
	int getm_Capacity()
	{
		return this->m_Capacity;
	}
	int getm_Size()
	{
		return this->m_Size;
	}

	//析构函数
	~MyArray()
	{
		//cout << "析构函数" << endl;

		if (this->pAdress != NULL);
		{
			delete[] pAdress;
			this->pAdress = NULL;	//防止野指针
		}
		
	}

private:
	T* pAdress; //指针指向堆区开辟真实数组
	int m_Capacity; //数组容量
	int m_Size; //数组大小
};

//总结:能够利用所学的知识实现通用数组