函数模板与类模板

模板

学习模板,使用模板让我们的代码能最大限度上的重用

一、模板的概念

1、模板与泛型编程

1.泛型编程:指的就是编写与类型无关的逻辑代码,在泛型编程中,编写的代码可以作用多种类型的对象

2.模板:就是实现代码重用的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了代码的重用性。模板就是泛型编程的基础

2、模板分类

1.函数模板

2类模板

二、函数模板

1、函数模板是什么

1.函数模板不是一个实体函数,编译器不会对一个函数模板生成可执行代码。定义函数模板之后只是说对一个函数功能框架的一个描述,只有在调用的时候才会为其生成可执行代码

2、函数模板的定义

1.定义:
template<typename T>
返回值类型  函数名(参数列表)
{
    函数体;
}
template:模板的关键字
<>:类型的参数列表
typename:用来声明类型参数,也可以用class
T:形参类型的名字
//注意:类型的参数列表中是可以有多个类型的,比如tempplate<typrname T1,typename T2>,写法和函数的形参列表写法一样

3、函数模板示例

template<typename T>
void fun(T &a,T &b)
{
    cout<<a<<endl<<b<<endl;
}
//定义:
int a=1,b=2;
char c='x';

4、函数模板和普通函数

1.函数模板和普通函数一样都是可以重载的,函数模板与普通函数也能构成重载

template<typename T>
void fun(T a, T b)
{
	cout << "我是函数模板" << endl;
}
void fun(int a, int b)
{
	cout << "我是普通函数" << endl;
}
template<typename T1, typename T2>
void fun(T1 a, T2 b)
{
	cout << "我是第二个函数模板" << endl;
}
//fun(1,'A');
//这样是调用的第三个fun函数,因为他会优先调用更好匹配的函数模板

2.如果出现了函数模板与普通函数之间的重载,优先调用普通函数

3.如果函数模板可以产生一个更好的匹配,那么选择模板

4.想要强制使用模板,那么就可以使用显示指定类型调用

5.函数模板实际上就是多了一个类型的参数列表,让我们在使用这个函数模板的时候可以传类型,定义了一个函数的框架,而不用确定类型,可以使用这个函数模板的时候再来确定类型

#include<iostream>
using namespace std;
//模板头,定义了类型的参数列表,可以传一个类型进来
//这个类型T可以在这个模板头下面的函数中进行使用
template<typename T>
T fun(T a, T b)
{
	return a + b;
}
/*
在调用的时候,编译器会把函数模板转为模板函数(确定T的类型)
int fun(int a,int b)
{
	return a+b;
}
*/
//隐式调用:函数模板会帮助我们自动去推导这个T的类型是什么类型
//函数模板的类型只有一个任意类型
//显示指定类型:给函数模板的类型参数,传一个具体的参数(类型),是可以有类型的自动转换的
int main()
{
	cout << fun(1, 2) << endl;//隐式调用
	cout << fun(1.2, 2.4) << endl;
	int x = fun('A', 'A');
	cout << x << endl;//-126----》中间要经过0
	cout << fun<char>(1, 'A') << endl;//显示指定类型,输出B
fun<>(1,2)//空参数列表也能强制调用函数模板
    //cout<<fun(1,'a');这样是不行的,必须显示指定类型
    //cout<<fun<int>(1,'a');空参数列表也不行
	system("pause");
	return 0;
}

5、模板的局限性

//模板在具体使用的过程中还是会出现一些问题
template<class T>
bool mycompare(T&a,T&b)
{
    if(a==b)
    {
        return true;
    }
    return false;
}
//这个函数模板在对于基本数据类型的比较是没有太大问题的,但是如果T是一个自定义数据类型,那么就不一定能用==来进行比较,所以在这里我们可以在自定义类型中加上重载运算符==来解决这个问题或者通过一个重载函数来处理
class person
{
    public:
    int x;
}
//重载函数
template<>bool mycompare<person>(perosn&a,person&b)
{
    if(a.x==a.x)
    {
        return true;
    }
    return false;
}

//解决方法
#include<iostream>
using namespace std;
template<class T>
bool mycompare(T&a, T&b)
{
	if (a == b)
	{
		return true;
	}
	return false;
}
class person
{
public:
	int x;
};
struct node
{
	int a, b;
	node()
	{
		a = 1, b = 2;
	}

};
//在c++中的结构体里面可以写的东西:在类中可以写的,在结构体里面也可以写,比如构造析构
//因为不能比较两个类
//解决方法:1.运算符重载==
//2.通过语法重载解决这个没有compare函数
//template<>返回值类型 函数名<具体的类型>(具体的类型定义的参数列表)
//3.单独写个函数比较,不用模板
template<>bool mycompare<person>(person&a, person&b)
{
	if (a.x == b.x)
		return true;
	return false;

}
//重载==
bool operator==(person& a, person& b)
{
	if (a.x == b.x)
		return true;
	return false;
}
int main()
{
	person p1, p2;
	p1.x = 10;
	p2.x = 10;
	cout << mycompare(p1, p2) << endl;


	system("pause");
	return 0;
}

三、类模板

1、类模板是什么

1.类模板与函数模板类似,也不是一个实体的类,理解为一个类的框架

2、类模板定义

template<类型参数列表>
class 类模板名
{
    成员函数和变量
}

3、类模板示例

template<class nametype,class agetype=int>//类模板也可以有默认类型,这是函数缺省
class person
{
    public:
    nametype name;
    agetype age;
    person(nametype name,agetype age)//在类模板中直接定义成员函数
    {
        this->name=name;
        this->age=age;
    }
    agetype getage();//在类模板中声明成员函数,在类外定义
}
template<class nametype,class agetype>//类模板外定义刚声明的函数
agetype person<nametype,agetype>::getage()
{
    return age;
}

4、类模板--动态数组

#include<iostream>
using namespace std;
template<typename T/*,typename T1,typename T2=int*/>
//类模板的类型参数同样可以缺省
class myarr
{
	T buff[100];//定义了一个数组
	int len;
public:
	myarr()//构造函数,初始化
	{
		memset(buff,0, sizeof(T) * 100);//初始化数组
		len = 0; 
	}
	void insert(int data)
	{
		buff[len++] = data;
	}
	void print()
	{
		for (int i = 0; i < len; i++)
		{
			cout << buff[i] << "\t";
		}
		cout << endl;
	}
};

int main()
{
	myarr<int> m1;//类模板不支持隐式推导类型,必须使用显示指定类型调用
	for (int i = 0; i < 10; i++ )
	{
		m1.insert(i + 1);
	}
	m1.print(); 
	myarr<char> m2;
	for (char i = 'a'; i <= 'z'; i++)
	{
		m2.insert(i);
	}
	m2.print();

	system("pause");
	return 0;
}

5、类模板做函数的参数

1、作为函数的传入实参
void dowork(perosn<string,int>&p){}
//把一个具体的类作为函数的参数
2、参数模板化
template<class T1,class T2>
void dowork(perosn<T1,T2>&p){}
//函数也是模板,且模板中的参数继续给类模板作为参数
3、整体模板化
template<class T>
void dowork(T&p){}
//可以把perosn<string,int> 整体当成T类型,比如
//perosn<string,int> myperson;
//dowork(myperson);

#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>//定义两个类模板
class person
{
public:
	T1 name;
	T2 age;//定义两个类模板里的成员
	person(T1 name, T2 age)
	{
		this->age = age;
		this->name = name;
	}
	void showperson()
	{
		cout << name << "\t" << age << endl;
	}
};

//拿具体的类类型当做形参,来接收实参
void fun(person<string, int>&p)
{
	p.showperson();
}
//参数模板化
template<class T1,class T2>
void fun1(person<T1, T2>&p)
{
	p.showperson();
}
//整体模板化
template<class T>
void fun2(T&p)
{
	p.showperson();
}
int main()
{
	person<string, int> p1("张飞", 500);
	p1.showperson();
	fun(p1);
	fun1(p1);//可以不写参数
	fun2(p1);
	system("pause");
	return 0;
}

6、类模板和继承

#include<iostream>
#include<string>
using namespace std;
template<class T1>
class base
{
public:
	T1 a;
};
template<class T1,class T2>
class child :public base<T1>
{
public:
	T2 b;
};
//如果父类是类模板,那么在定义子类的对象的时候,是需要构造父类的成员的
//如果父类的这个任意类型T1不知道是什么类型,那么无法定义成员a(无法定义父类的成员),就需要在继承的时候,告诉父类的这个T1是什么类型
int main()
{
	child<int, int> c;
	
	system("pause");
	return 0;
}

7、类模板不能分模板编写

1.类模板中成员函数的创建时在调用阶段,那么就会导致在分文件编写的时候链接不到,即不能分文件编写类模板

2.解决方法,直接将声明和实现写到同一个文件中,把后缀名改为.hpp,.hpp是一个约定俗成的名称

person.h

写在同一个文件下面

#pragma once
#include<stdio.h>
template<class T>
class person
{
public:
	T n;
	void fun();
};

template<class T>
inline void person<T>::fun()
{
	printf("aaaa");
}

源.cpp

#include<iostream>
#include"person.h"
using namespace std;

int main()
{
	person<int> p;
	p.fun();
	
	system("pause");
	return 0;
}
#include<iostream>
using namespace std;
class A
{
public:
	void Afun()
	{
		cout << "A的fun函数" << endl;
	}
};
class B
{
public:
	void Bfun()
	{
		cout << "B的fun函数" << endl;
	}
};
template<class T>
class CC
{
	T t;
public:
	void funa()
	{
		t.Afun();
	}
	void funb()
	{
		t.Bfun();
	}
	T fun1(T a);
	void fun2();
};
template<class T>
T CC<T>::fun1(T a)
{
	return T;
}
template<class T>
void CC<T>::fun2()
{

}
int main()
{
	CC<A> c;
	c.funa();
	system("pause");
	return 0;
}

类模板中实现友元函数

#include<iostream>
using namespace std;
//类模板中实现友元函数
template<class T>
class person
{
	T id;
public:
	friend void print(person<T>&p)
		cout << p.id << endl;
	person(T id)//带参构造
	{
		this->id = id;
	}
};
int main()
{
	person<int> p(99);
	print(p);
	system("pause");
	return 0;
}

类外实现友元函数---较麻烦

#include<iostream>
using namespace std;

//类模板向前声明
template<class T>
class person;
//函数模板向前声明
template<class T>
void print(person<T>&p);

template<class T>
class person
{
	T id;
public:
	
	person(T id)//带参构造
	{
		this->id = id;
	}
	friend void print<>(person<T>&p);
};
template<class T>
void print(person<T>&p)
{
	cout << p.id << endl;
}//这里只是一个逻辑代码
int main()
{
	person<int> p(33);
	print(p);
	system("pause");
	return 0;
}
posted @ 2021-03-03 19:35  kisfly  阅读(189)  评论(0编辑  收藏  举报