模板————类模板

.1 类模板语法

template<class NameType,class AgeType> 			//包含两个成员属性,所以用两个T

class Person {
public:
	NameType m_name;
	AgeType m_age;
};

Person<string, int> p;							//实例化只能用显示指定类型

.2 类模板与函数模板的区别

  1. 类模板 没有自动类型推导的使用方式
  2. 类模板 在模板参数列表中可以有默认参数
template<class NameType,class AgeType=int> 		//默认参数

class Person {
public:
	NameType m_name;
	AgeType m_age;
};

Person<string> p;								//则实列化时可以去掉一个参数

.3 类模板中成员函数创建时机

  1. 普通类中的成员函数一开始就可以创建
  2. 类模板中的成员函数在调用时才创建
    在编译生成时才会报错(暂时不知道有什么实用价值)
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 类模板对象作为函数参数

传入方式有三种:

  1. 指定传入的类型----直接显示对象的数据类型
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);
}
  1. 参数模板化 ----将对象中的参数变为模板进行传递
    利用typeid(T1).name()可知类型
template<class T1, class T2>				//需要加上声明
void printPerson(Person <T1,T2>& p) {
	cout << "成功传参" << endl;
	cout << "T1的类型是:" << typeid(T1).name() << endl;
}
  1. 整个类模板化 —将这个对象类型模板化进行传递
template<class T>				//将Person类看作模板
void printPerson(T& p) {
	cout << "成功传参" << endl;
	cout << "T的类型是:" << typeid(T).name() << endl;
}

.5 类模板与继承

  1. 子类继承的父类是一个模板时,子类在声明时,要确定下来父类中T的类型
template<class T1,class T2>
class Person {
public:
	T1 name;
	T2 age;
};

class Chinese :public Person <string, int> {		//需要指出
public:
};
  1. 若子类仍然想灵活使用父类的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;				//大小即元素个数
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值