首页 > 其他分享 >62.类模板

62.类模板

时间:2023-03-09 22:59:09浏览次数:29  
标签:name age Person 62 template public 模板

1.类模板

1.1类模板基本概念

  函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板

●类模板用于实现类所需数据的类型参数化

template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

void test01()
{
	//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
	Person<string, int>P1("德玛西亚", 18);
	P1.showPerson();
}

1.2类模板做函数参数

//类模板
template<class NameType, class AgeType>
class Person{
public:
	Person(NameType name, AgeType age){
		this->mName = name;
		this->mAge = age;
	}
	void PrintPerson(){
		cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

//类模板做函数参数
void DoBussiness(Person<string,int>& p){
	p.mAge += 20;
	p.mName += "_vip";
	p.PrintPerson();
}

int main(){

	Person<string, int> p("John", 30);
	DoBussiness(p);

	system("pause");
	return EXIT_SUCCESS;
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>

//普通类继承类模版
template<class T>
class Father
{
public:
	Father()
	{
		m = 20;
	}
public:
	T m;
};

//普通类 继承 类模版
class Son :public Father<int>//要告诉编译器父类的泛型数据类型具体是什么类型
{
public:

};
//类模版 继承 类模版
template<class T1,class T2>
class Son2 :public Father<T2>//要告诉编译器父类的泛型数据类型具体是什么类型
{

};

void test()
{
	Son2<int,int> s;
	cout << s.m << endl;
}

int main()
{
	test();

	system("pause");
	return EXIT_SUCCESS;
}

3.类模板派生普通类

#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <string>
using namespace std;

//类模板
template<class T>
class MyClass {
public:
	MyClass(T property) {
		this->mProperty = property;
	}
public:
	T mProperty;
};

//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的
//这样c++编译器才能知道给子类分配多少内存

//普通派生类
class SubClass : public MyClass<int> {
public:
	SubClass(int b) : MyClass<int>(20) {
		this->mB = b;
	}
public:
	int mB;
};

int main()
{
	SubClass son(1);
	cout << "son.mProperty:" << son.mProperty << "," << "son.mB:" << son.mB << endl;
    system("pause");
    return EXIT_SUCCESS;
}

输出:

son.mProperty:20,son.mB:1
请按任意键继续. . .

1.4模板派生类模板

//父类类模板
template<class T>
class Base
{
	T m;
};
template<class T >
class Child2 : public Base<double>  //继承类模板的时候,必须要确定基类的大小
{
public:
	T mParam;
};

void test02()
{
	Child2<int> d2;
}

1.5类模板类内实现

template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

void test01()
{
	//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 
	Person<string, int>P1("德玛西亚", 18);
	P1.showPerson();
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>

template<class NameType, class AgeType>
class Maker
{
public:
	Maker(NameType name, AgeType age);
	/*{
		this->name = name;
		this->age = age;
	}*/

	void printMaker();
	/*{
		cout << "Name:" << this->name << " Age:" << this->age << endl;
	}*/
public:
	NameType name;
	AgeType age;
};

//类模版的成员函数类外实现
//要写成函数模版
template<class NameType, class AgeType>
Maker<NameType, AgeType>::Maker(NameType name, AgeType age)
{

	cout << "构造函数" << endl;
	this->name = name;
	this->age = age;
}


template<class NameType, class AgeType>
void Maker<NameType, AgeType>::printMaker()
{
	cout << "Name:" << this->name << " Age:" << this->age << endl;
}

int main()
{
	Maker<string, int> m("haha", 20);
	m.printMaker();
	system("pause");
	return EXIT_SUCCESS;
}

1.6类模板类外实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

template<class T1, class T2>
class Person{
public:
	Person(T1 name, T2 age);
	void showPerson();

public:
	T1 mName;
	T2 mAge;
};


//类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
	this->mName = name;
	this->mAge = age;
}


template<class T1, class T2>
void Person<T1, T2>::showPerson(){
	cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

void test()
{
	Person<string, int> p("Obama", 20);
	p.showPerson();
}

int main(){

	test();

	system("pause");
	return EXIT_SUCCESS;
}

1.7类模板头文件和源文件分离问题

Person.hpp

#pragma once

template<class T1,class T2>
class Person{
public:
	Person(T1 name,T2 age);
	void ShowPerson();
public:
	T1 mName;
	T2 mAge;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
	this->mName = name;
	this->mAge = age;
}

template<class T1, class T2>
void Person<T1, T2>::ShowPerson(){
	cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>
#include"Person.hpp"

//模板二次编译
//编译器编译源码 逐个编译单元编译的

int main(){

	Person<string, int> p("Obama", 20);
	p.ShowPerson();


	system("pause");
	return EXIT_SUCCESS;
}

结论: 案例代码在qt编译器顺利通过编译并执行,但是在Linux和vs编辑器下如果只包含头文件,那么会报错链接错误,需要包含cpp文件,但是如果类模板中有友元类,那么编译失败!

解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).

原因:

类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。

C++编译规则为独立编译

1.8模板类碰到友元函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

template<class T1, class T2> class Person;
//告诉编译器这个函数模板是存在
template<class T1, class T2> void PrintPerson2(Person<T1, T2>& p);

//友元函数在类内实现
template<class T1, class T2>
class Person{
	//1. 友元函数在类内实现
	friend void PrintPerson(Person<T1, T2>& p){
		cout << "Name:" << p.mName << " Age:" << p.mAge << endl;
	}

	//2.友元函数类外实现
	//告诉编译器这个函数模板是存在
	friend void PrintPerson2<>(Person<T1, T2>& p);

	//3. 类模板碰到友元函数模板
	template<class U1, class U2>
	friend void PrintPerson(Person<U1, U2>& p);

public:
	Person(T1 name, T2 age){
		this->mName = name;
		this->mAge = age;
	}
	void showPerson(){
		cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
	}
private:
	T1 mName;
	T2 mAge;
};

void test01()
{
	Person <string, int>p("Jerry", 20);
	PrintPerson(p);
}


// 类模板碰到友元函数
//友元函数类外实现  加上<>空参数列表,告诉编译去匹配函数模板
template<class T1 , class T2>
void PrintPerson2(Person<T1, T2>& p)
{
	cout << "Name2:" << p.mName << " Age2:" << p.mAge << endl;
}

void  test02()
{
	Person <string, int>p("Jerry", 20);
	PrintPerson2(p);   //不写可以编译通过,写了之后,会找PrintPerson2的普通函数调用,因为写了普通函数PrintPerson2的声明	
}

int main(){

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>


template<class NameType, class AgeType>
class Maker
{
	friend void printMaker(Maker<NameType, AgeType> &p)
	{
		cout << "类内实现" << p.name << " " << p.age << endl;
	}
public:
	Maker(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	
private:
	NameType name;
	AgeType age;
};

void test01()
{
	Maker<string, int> m("悟空", 18);

	printMaker(m);
}

template<class NameType, class AgeType>
class Maker2;

//告诉编译器下面有printMaker2的实现
template<class NameType, class AgeType>
void printMaker2(Maker2<NameType, AgeType> &p);

template<class NameType, class AgeType>
class Maker2
{
	//1.在函数名和()之间加上<>。(使得可以去找函数模板)
	friend void printMaker2<>(Maker2<NameType, AgeType> &p);
	//2.编译器不知道printMaker2下面有没有实现,需要知道函数的结构
public:
	Maker2(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}


private:
	NameType name;
	AgeType age;
};

//友元在类外实现要写成函数模版
template<class NameType, class AgeType>
void printMaker2(Maker2<NameType, AgeType> &p)
{
	cout << "类外实现的友元函数 " << p.name << " " << p.age << endl;
}

void test02()
{
	Maker2<string, int> m("贝吉塔", 18);

	printMaker2(m);
}

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

2.类模板的应用

设计一个数组模板类(MyArray),完成对不同类型元素的管理

类模版实现数组.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include"MyArray.hpp"
#include<string>
class Maker
{
public:
	Maker(){}
	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
public:
	string name;
	int age;
};

void printMaker(MyArray<Maker> &arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << endl;
	}
}
void test()
{
	MyArray<Maker> myarr(4);
	Maker m1("悟空", 18);
	Maker m2("贝吉塔", 30);
	Maker m3("短笛", 200);
	Maker m4("小林", 19);
	myarr.Push_Back(m1);
	myarr.Push_Back(m2);
	myarr.Push_Back(m3);
	myarr.Push_Back(m4);

	printMaker(myarr);

	MyArray<int> myint(10);
	for (int i = 0; i < 10; i++)
	{
		myint.Push_Back(i + 1);
	}

	for (int i = 0; i < 10; i++)
	{
		cout << myint[i] <<" ";
	}
	cout << endl;
}

int main()
{
	test();

	system("pause");
	return EXIT_SUCCESS;
}

MyArray.hpp

#pragma once

template<class T>
class MyArray
{
public:
	MyArray(int capacity)
	{
		this->mCapacity = capacity;
		this->mSize = 0;
		//T如果是Maker,这里要调用什么构造函数,要调用无参构造
		p = new T[this->mCapacity];

	}

	//拷贝构造
	MyArray(const MyArray &arr)
	{
		this->mCapacity = arr.mCapacity;
		this->mSize = arr.mSize;
		p = new T[arr.mCapacity];

		for (int i = 0; i < this->mSize; i++)
		{
			p[i] = arr.p[i];
		}
	}
	//赋值函数
	MyArray &operator=(const MyArray &arr)
	{
		if (this->p != NULL)
		{
			delete[] this->p;
			this->p = NULL;
		}

		p = new T[arr.mCapacity];
		this->mSize = arr.mSize;
		this->mCapacity = arr.mCapacity;
		for (int i = 0; i < this->mSize; i++)
		{
			p[i] = arr.p[i];

		}

		return *this;
	}

	//重载[]
	T &operator[](int index)
	{
		return this->p[index];
	}
	//尾插
	void Push_Back(const T &val)
	{
		if (this->mSize == this->mCapacity)
		{
			return;
		}

		this->p[this->mSize] = val;
		this->mSize++;
	}

	//尾删
	void Pop_Back()
	{
		if (this->mSize == 0)
		{
			return;
		}

		this->mSize--;
	}

	~MyArray()
	{
		if (this->p != NULL)
		{
			delete[] p;
			p = NULL;
		}
	}

	int getSize()
	{
		return this->mSize;
	}
private:
	T *p;
	int mCapacity;
	int mSize;
};

标签:name,age,Person,62,template,public,模板
From: https://www.cnblogs.com/codemagiciant/p/17201793.html

相关文章

  • 广搜模板
    //广搜模板LinkedList<Node>linkedList=newLinkedList<>();linkedList.addLast(newNode(0,0));//入队while(!linkedList.isEmpty()){ Nodea=linkedList.......
  • vue3.0 如何获得引用element plus的messagebox模板如何写回调函数
    1.比如找到官网的这个messagebox,复制原文,然后我们来试一试如何添加回调函数吧<scriptlang="ts"setup>import{ElMessage,ElMessageBox}from'element-plus'c......
  • [Primer] 第 16 章 string 类和标准模板库
    第16章string类和标准模板库16.1string类16.2智能指针模板类要创建智能指针对象,必须包含头文件<memory>。离开代码块后,智能指针将自动释放内存。声明只能指针......
  • IDEA类和方法注释模板设置(非常详细)
    类注释模板File-->settings-->Editor-->FileandCodeTemplates-->Files我们选择Class文件(当然你要设置接口的还也可以选择Interface文件)${NAME}:设置类名,与下面的${......
  • .grf 读入报表模板失败,请检查网络连接、URL及读取权限,错误提示:网络服务器响应不成功
    http://xxx.xxx.xxx.xxx:xxx/Pages/QySqdInfo/../../GrfFile/Qianyue/qianyue_3303.grf从'http://xxx.xxx.xxx.xxx:xxx/Pages/QySqdInfo/../../GrfFile/Qianyue/qianyue_330......
  • 62、快速操作工具—模糊背景
    1、双击背景图,然后【ctrl+j】复制一个图层2、点击【帮助】—>【Photoshop帮助】—>【快速操作】—>【模糊背景】—>【高斯模糊】3、然后选择【调整画笔边缘工具】,设置画......
  • C++ 三路快排 模板
    前言:今天被大作业的快速排序折磨的焦头烂额,原C++sort选手发现简洁的快排竟然如此难写(边界要注意的点好多qwq)。我原先的快排长这样:题解P1177【【模板】快速排序】......
  • CF628B 1300
    题意解析末尾2位是4的倍数即可。每次特判最后一位。代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=3e5+10;strings;b......
  • P3378 【模板】堆
    P3378【模板】堆【模板】堆题目描述给定一个数列,初始为空,请支持下面三种操作:给定一个整数x,请将x加入到数列中。输出数列中最小的数。删除数列中最小的数(如果有......
  • 设计模式(十七)----行为型模式之模板方法模式
    行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为......