fqy131314

类模板总结

所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

函数模板定义形式

  由以下三部分组成:  模板说明 + 函数定义 + 函数模板调用

  template < 类型形式参数表 >

  类型  函数名 (形式参数表)

{

    //语句序列

}

1. 模板说明  

template    < 类型形式参数表 >  

类型形式参数的形式:

typename T1 ,  typename T2 , …… , typename Tn 

class T1 ,  class T2 , …… , class Tn

(:typename 和 class 的效果完全等同)

2. 函数定义

 类型  函数名  (形式参数表)

{

}

注意:模板说明的类属参数必须在函数定义中出现一次

      函数参数表中可以使用类属类型参数,也可以使用一般类型参数

3. 函数模板调用

max<int>(a, b);  //显式类型调用

max(a, b);   //自动数据类型推导

函数模板和普通函数区别结论: 

两者允许并存

函数模板不允许自动类型转化

函数模板和普通函数在一起,调用规则:

1 函数模板可以像普通函数一样被重载

2 C++编译器优先考虑普通函数

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

4 可以通过空模板实参列表的语法限定编译器只通过模板匹配

结论:

1. 编译器并不是把函数模板处理成能够处理任意类型的函数

2. 编译器从函数模板通过具体类型产生不同的函数

2.类模板定义

   类模板由模板说明和类说明构成

   模板说明同函数模板,如下:

         template    <类型形式参数表>

         类声明

例如:

   template  <typename Type>

class ClassName

{

//ClassName 的成员函数

   private :

   Type DataMember;

}

1.父类一般类,子类是模板类, 和普通继承的玩法类似

2.子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数

3.父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中

总结:

在同一个cpp 文件中把模板类的成员函数放到类的外部,需要注意以下几点

  1. 函数前声明 template    <类型形式参数表>
  2. 类的成员函数前的类限定域说明必须要带上虚拟参数列表
  3. 返回的变量是模板类的对象时必须带上虚拟参数列表
  4. 成员函数参数中出现模板类的对象时必须带上虚拟参数列表
  5. 成员函数内部没有限定

注意:当类模板的声明(.h文件)和实现(.cpp 或.hpp文件)完全分离,因为类模板的特殊实现,我们应在使用类模板时使用#include 包含 实现部分的.cpp 或.hpp文件。

  1. 类内部声明友元函数,必须写成一下形式

    template<typename T>

friend A<T> addA (A<T> &a, A<T> &b);

  1. 友元函数实现 必须写成

template<typename T>

  A<T> add(A<T> &a, A<T> &b)

{

//......

}

  1. 友元函数调用 必须写成

A<int> c4 = addA<int>(c1, c2);

总结:

  • 从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
  •  和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
  • static 数据成员也可以使用虚拟类型参数T

6.类模板使用总结

归纳以上的介绍,可以这样声明和使用类模板:

1) 先写出一个实际的类。

2) 将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的T)。

3) 在类声明前面加入一行,格式为:

    template <typename 虚拟类型参数>

如:

    template <typename numtype>

    class A

    {…}; //类体

4) 用类模板定义对象时用以下形式:

    类模板名<实际类型名> 对象名;

    或 类模板名<实际类型名> 对象名(实参表列);

如:

    A<int> cmp;

    A<int> cmp(3,7);

5) 如果在类模板外定义成员函数,应写成类模板形式:

   template <typename 虚拟类型参数>

   函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列) {…}

关于类模板的几点补充

1) 类模板的类型参数可以有一个或多个,每个类型前面都必须加typename 或class,如:

    template <typename T1,typename T2>

    class someclass

    {…};

在定义对象时分别代入实际的类型名,如:

    someclass<int, char> object;

2) 和使用类一样,使用类模板时要注意其作用域,只有在它的有效作用域内用使用它定义对象。

3) 模板类也可以有支持继承,有层次关系,一个类模板可以作为基类,派生出派生模板类。

代码如下:

main.h

#include "Vector.cpp"
#include <iostream>
#include <Windows.h>


class Student
{
public:
	Student(const char* _name, int _age)
	{
		strcpy_s(name, 64, _name);
		age = _age;
	}

	~Student()
	{

	}

	Student()
	{
		age = 0;
		name[0] = NULL;
	}

	friend ostream& operator<<(ostream& os, const Student& object);

private:
	char name[64];
	int age;

};
int main(void)
{
	Vector<int> studentVector(10);

	for (int i = 0; i < studentVector.getLength(); i++)
	{
		studentVector[i] = i;
	}

	//依次序打印
	for (int i = 0; i < studentVector.getLength(); i++)
	{
		cout << studentVector[i] << endl;
	}

	//全部打印
	cout << studentVector << endl;



	//float类型
	Vector<float> studentVector1(10);

	for (int i = 0; i < studentVector1.getLength(); i++)
	{
		studentVector1[i] = i * 0.1f;
	}

	//依次序打印
	for (int i = 0; i < studentVector1.getLength(); i++)
	{
		cout << studentVector1[i] << endl;
	}

	//全部打印
	cout << studentVector1 << endl;

	Student s1("李小双", 28);
	Student s2("俩后", 40);

	Vector<Student> studentVector3(2);

	studentVector3[0] = s1;
	studentVector3[1] = s2;

	//依次序打印
	for (int i = 0; i < studentVector3.getLength(); i++)
	{
		cout << studentVector3[i] << endl;
	}

	//整体打印
	cout << studentVector3 << endl;

	system("pause");
	return 0;
}

ostream& operator<<(ostream& os, const Student& object)
{
	os << "姓名:" << object.name << "年龄:" << object.age << endl;

	return os;

}

Vector.h


#include <iostream>

using namespace std;

template <typename T>
class Vector
{
public:
	template <typename T>
	friend ostream& operator<< <T> (ostream& os, const Vector<T>& object);

public:
	Vector(int m_len=128);
	~Vector();
	
	Vector(const Vector& object);
	int getLength();
	T& operator[](int i);

	

	Vector& operator=(const Vector& object);


private:
	int m_len;
	T* m_size;

};

template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& object);

Vector.cpp

#include "Vector.h"

template <typename T>
Vector<T>::Vector<T>(int size)
{
	this->m_len = size;
	//分配内存大小
	this->m_size = new T[m_len];
}

template <typename T>
Vector<T>::~Vector()
{
	if (m_size != NULL)
	{
		delete[] m_size;
		m_size = NULL;
		m_len = 0;
	}
}

template <typename T>
int Vector<T>::getLength()
{
	return m_len;
}

template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& object)
{
	for (int i = 0; i < object.m_len; i++)
	{
		os << object.m_size[i] << endl;
	}

	return os;
}

template <typename T>
T& Vector<T>::operator[](int i)
{
	return m_size[i];
}

template <typename T>
Vector<T>::Vector<T>(const Vector<T>& object)
{
	if (m_size != NULL)
	{
		delete[] m_size;
		m_size = NULL;
		m_len = 0;
	}

	//分配内存
	this->m_len = object.m_len;
	this->m_size = new T[this->m_len];

	//赋值
	for (int i = 0; i < object.m_len; i++)
	{
		this->m_size[i] = object.m_size[i];
	}
}

//赋值构造函数
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& object)
{
	if (this->m_size != NULL)
	{
		delete[] m_size;
		m_len = 0;
		m_size = NULL;
	}

	this->m_len = object.m_len;
	this->m_size = new T[this->m_len];

	for (int i = 0; i < object.m_len; i++)
	{
		this->m_size[i] = object.m_size[i];
	}

}

posted on   会飞的鱼-blog  阅读(12)  评论(0编辑  收藏  举报  

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示